Logo __vector__ 的博客

博客

How to AK ABC252

...
__vector__
2025-12-01 12:55:45

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-05-22 14:48:23

前言:

被 D 题降智,E 题写了个 kruskal 结果被卡了,F 题是个普及组难度的原题但是我没去看,最后 rating:
$\color{brown}\text{706} \rightarrow \color{brown}\text{725}$,什么时候才能上 $\color{green}\text{6kyu}$

A

int ch=getchar();
cout<<char(ch);
两行代码结束。
复杂度:$O(1)$

B

这个东西直接模拟就行了。
复杂度:$O(n+k)$

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
	const int maxn=105;
	int a[maxn],b[maxn];
	int k,n;
	int imax=0;
	void main()
	{
		cin>>n>>k;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			imax=max(imax,a[i]);
		}
		for(int i=1;i<=k;i++)
		{
			cin>>b[i];
			if(a[b[i]]==imax)
			{
				printf("Yes");
				return;
			}
		}
		printf("No");
		
	}
}
int main()
{
	Main::main();
	return 0;
}

C

可以枚举 $0 \rightarrow 9$ 代表最终每个都显示的数字,然后枚举每一秒,每一秒再枚举每个可以点击的按钮即可。
算一下就可以发现,最多 1000 秒就能使所有的卷轴显示相同的数字,因为极端情况下 $10$ 秒才能控制一个卷轴,最多有 $n$ 个卷轴,$n \le 100$,$10 \times 100 = 1000$。
总复杂度: $O(10 \times 1000 \times n) = O(10000n)$

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
	const int maxn=105;
	char s[maxn][15];
	int n;
	bool vis[maxn];
	void main()
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%s",s[i]);
		}
		int ans=0x3f3f3f3f;
		for(int i=0;i<10;i++)\/\/zimu
		{
			int col=0;
			for(int t=0;t<=1000;t++)\/\/miaoshu
			{
				bool flag=1;
				for(int j=1;j<=n;j++)
				{
					if(!vis[j])
					{
						if(s[j][t%10]==(i+'0'))
						{
							vis[j]=1;
							break;
						}
					}
				}
				for(int j=1;j<=n;j++)
				{
					if(!vis[j])
					{
						flag=0;
						break;
					}
				}
				if(flag)
				{
					col=t;
					break;
				}
			}
			ans=min(ans,col);
			for(int j=1;j<=n;j++)
			{
				vis[j]=0;
			}
		}
		printf("%d",ans);
	}
}
int main()
{
	Main::main();
	return 0;
}

D

可以先计算所有情况,然后再减去不合法情况。
假设由有 $n$ 个元素,那么在其中任意选择 $3$ 个元素的情况有 $\dfrac{n \cdot (n-1) \cdot (n-2)}{6}$ 个,任意选择 $2$ 个元素的情况有 $\dfrac{n \cdot (n-1)}{2}$ 个。
那么先定义两个函数,方便后面使用:

long long sum_3(long long n)
{
	return n*(n-1)*(n-2)\/6;
}
long long sum_2(long long n)
{
	return n*(n-1)\/2;
}

设一个元素 $a_i$ 在数组中重复出现了 $x$ 次,数组有 $n$ 个元素。将会出现两种不合法情况,来分类一下。

  1. 第一种情况是三元组的组成元素全都是 $a_i$,这种情况有 $\dfrac{x \cdot (x-1) \cdot (x-2)}{6}$个,也就是 sum_3(x)
  2. 第二种情况是三元组的两个元素是 $a_i$,直接在数组所有重复的 $a_i$ 中挑选有 $\dfrac{x \cdot (x-1)}{2}$ 个组合,显然,每个组合都会与其他 $n-2$ 个元素形成新的组合,有 $\dfrac{x \cdot (x-1)}{2} \cdot (n-2)$ 个情况。但是别忘了,其中有 $\dfrac{x \cdot (x-1)}{2} \cdot (x-2)$ 种情况会组合成三个元素都相等的三元组,而这些情况已经在第一条处理过,这里不需要再处理,所以实际上只用处理 $\dfrac{x \cdot (x-1)}{2} \cdot [n-2-(x-2)]=\dfrac{x \cdot (x-1)}{2} \cdot (n-x)$ 个情况

综上,设每个元素出现了 $x_i$,数组有 $n$ 个元素,那么答案就是:
$\dfrac{n \cdot (n-1) \cdot (n-2)}{6} - \sum_{i=1}^{n} (\dfrac{x_i \cdot (x_i-1) \cdot (x_i-2)}{6} + \dfrac{x_i \cdot (x_i-1)}{2} \cdot (n-x_i))$
复杂度 $O(n)$(unordered_map 是 $O(1)$的)

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
	typedef long long ll;
	const int maxn=2e5+5;
	unordered_map<int,int> im;
	int a[maxn];
	int n;
	ll sum_3(ll n)
	{
		return n*(n-1)*(n-2)\/6ll;
	}
	ll sum_2(ll n)
	{
		return n*(n-1)\/2ll;
	}
	void main()
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			im[a[i]]++;
		}
		ll ans=sum_3(n);
		for(int i=1;i<=n;i++)
		{
			if(im[a[i]])
			{
				ans-=sum_3(im[a[i]]);
				ans-=sum_2(im[a[i]])*ll(n-im[a[i]]);
				im[a[i]]=0;
			}
		}
		printf("%lld",ans);

	}
}
int main()
{
	Main::main();
	return 0;
}

E

不懂 prim请自行百度
这道题让构造一棵树使得 $1$ 到每个点的距离之和最短。最短路 + 生成树,那么肯定就是 prim(赛时我不会 prim,所以寄了)。
这道题算是把堆优化版 prim 板子改改就能过的那种,来说一下:

  1. 把更新最短路的地方改成 dijkstra 的做法。
  2. pair 的第一个关键字来存储边权,第二个关键字存储边的编号。当要取出队首节点时,直接取出 edge[que.top().second].to 即可。
  3. 如果 $1$ 点存入小根堆种,取出队首节点时不会取出 $1$ 点,而是取出 $1$ 指向的节点,所以应该建立一个 $0$ 号节点并将其连向 $1$ 节点,初始时将 $0$ 号节点压入小根堆。
  4. 用一个 queue<int> ans 来存储每个需要的边,每弹出队首,就将这条边加入其中,也就是:int id=que.top().second; ans.push((id+1)\/2); 注:之所以 $id$ 要加 $1$ 然后除以 $2$ 是因为建图的时候建的双向边,编号为 $1,2$ 的是一条边,编号为 $3,4$ 的是一条边..........

这道题就结束了。
复杂度: $O((n+m)logm)$

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
	typedef long long ll;
	const int maxn=2e5+5;
	const int maxm=2e5+5;
	int head[maxn<<1];
	bool vis[maxn];
	ll dis[maxn];
	struct EDGE
	{
		int to,nxt,val;
	}edge[maxm<<1];
	int cnt;
	inline void add(int u,int to,int val)
	{
		edge[++cnt].to=to;
		edge[cnt].val=val;
		edge[cnt].nxt=head[u];
		head[u]=cnt;
	}
	int n,m;
	inline void prim()
	{
		queue<int> ans;
		priority_queue<pair<ll,int>> que;
		for(int i=0;i<=n;i++)
		{
			dis[i]=1e18;
		}
		dis[1]=0;
		que.push(make_pair(0,m*2+1));
		int tot=0;
		while(tot<n&&!que.empty())
		{
			int id=que.top().second;
			int u=edge[id].to;		
			que.pop();
			if(vis[u])continue;
			vis[u]=1;
			ans.push(((id+1)>>1));
			tot++;
			for(int i=head[u];i;i=edge[i].nxt)
			{
				int to=edge[i].to;
				if(dis[to]>dis[u]+ll(edge[i].val))
				{
					dis[to]=dis[u]+ll(edge[i].val);
					que.push(make_pair(-dis[to],i));
				}
			}
		}
		ans.pop();
		while(ans.size()!=0)
		{
			printf("%d ",ans.front());
			ans.pop();
		}
	}
	void main()
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			int xi,yi,zi;
			scanf("%d%d%d",&xi,&yi,&zi);
			add(xi,yi,zi);
			add(yi,xi,zi);
		}
		add(0,1,0);
		prim();
	}
}
int main()
{
	Main::main();
	return 0;
}

F

这道题是 合并果子 原题,相信谁都会我就不说了
大意:给定一个大小为 $l$ 的面包,要将面包分成 $n$ 块,第 $i$ 块面包大小为 $a_i$。
每次可以将一块面包切成两个任意大小的面包。每次切割面包都会产生相当于原来面包大小的代价,问完成操作的最小代价是多少。
把这个过程倒过来,变成合并面包就行了。现在问题转化为有 $n$ 个大小为 $a_i$ 的面包和一个大小为 $l - \sum a_i$ 的面包,每次可以合并任意两个面包,合并的代价为两个面包大小之和。问合并出一个大小为 $l$ 的面包的最小代价。
显然,每次选出大小最小的两个面包合并就能保证最后代价最小,用小根堆维护即可。
复杂度:$O(nlogn)$

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
	typedef long long ll;
	const int maxn=2e5+5;
	ll a[maxn];
	priority_queue<ll> que;
	int n;
	ll l;
	void main()
	{
		scanf("%d%lld",&n,&l);
		ll ans=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
			que.push(-a[i]);
			l-=ll(a[i]);
		}
		if(l>0)
		{
			que.push(-l);
		}
		n=que.size();
		for(int i=1;i<n;i++)
		{
			ll t1=-que.top();
			que.pop();
			ll t2=-que.top();
			que.pop();
			ans+=t1+t2;
			que.push(-t1-t2);
		}
		printf("%lld",ans);
	}
}
int main()
{
	Main::main();
	return 0;
}

Ex

题目简略翻译:

有 $C$ 个美丽值,分别为 $1,2,......C$
有 $N$ 个宝石,每个宝石都有一个颜色 $D_i$,和一个美丽值 $V_i$($V_i \in {1,2,.....C}$,每个美丽值都至少会在某个宝石上出现一次)

现在要在 $n$ 个宝石中选 $C$ 个颜色互不相同的宝石,每个方案的价值是选择的这 $C$ 个宝石的美丽值的异或和。
问价值为第 $k$ 大的方案的价值

题目分析:

老子不会

代码:

#include <bits\/stdc++.h>
using namespace std;
int main()
{
	cout<<"老子不会";  
   return WA;
}  

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。