首页 > 其他分享 >Atcoder Grand Contest 016

Atcoder Grand Contest 016

时间:2023-11-04 19:33:36浏览次数:37  
标签:Atcoder ch Contest int while le 016 isdigit getchar

给我贺完了?


A - Shrinking

给定一个串 \(s\),每次可以进行如下操作:

  • 记串长为 \(n\).

  • 构造长为 \(n-1\) 的串 \(s'\),满足 \(s'_i\) 为 \(s_i\) 或 \(s_{i+1}\),令 \(s\leftarrow s'\).

问使 \(s\) 中所有字符相同的最小操作次数。\(|s|\le 100\).


按照题意模拟即可,时间复杂度 \(O(|\Sigma|\cdot |s|^2)\),此处 \(|\Sigma|=26\).

点击查看代码
#include<bits/stdc++.h>
#define N 105
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
int n;char s[N];int t[N],tp[N];
int ans=114514;
void solve(int x){
	bool exi=false;
	for(int i=1;i<=n;i++)
		exi|=((tp[i]=s[i]-'a')==x);
	if(!exi)return;
	int cnt=0;
	for(int o=1;o<n;o++){
		bool fl=true;
		for(int j=1;j<=n-o+1;j++)
			if(tp[j]!=x){fl=false;break;}
		if(fl)break;
		cnt++;
		for(int j=1;j<=n-o;j++)
			t[j]=(tp[j]==x||tp[j+1]==x)?x:tp[j];
		memcpy(tp,t,sizeof(tp));
	}
	ans=min(ans,cnt);
}
int main(){
	scanf("%s",s+1),n=strlen(s+1);
	for(int i=0;i<26;i++)solve(i);
	printf("%d\n",ans);
	
	return 0;
}

B - Colorful Hats

\(n\) 只猫戴帽子,\(a_i\) 表示除第 \(i\) 只猫外的帽子颜色总数,问是否存在合法的帽子颜色序列。

\(2\le n\le 10^5\),\(1\le a_i\le n-1\).


记 \(L,R\) 分别为 \(\{a_n\}\) 中的最小值和最大值。

不难发现 \(L=R\) 或 \(L+1=R\),否则无解。

称出现一次的帽子为奇异帽子,反之为平凡帽子。

  • \(L=R\)

此时所有猫戴奇异帽子或平凡帽子。

得到 \(L=n-1\) 或 \(n\ge 2L\).

  • \(L=R+1\)

若 \(a_i=L\),其一定戴奇异帽子,反之戴平凡帽子。考虑帽子颜色种数的上下界。

记 \(a_i=L\) 的 \(i\) 有 \(cl\) 个,\(a_i=R\) 的有 \(cr\) 个。

不难发现 \(R\) 即帽子颜色总数。

若平凡帽子颜色均相同,帽子颜色总数最小为 \(cl+1\).

若每种平凡帽子只出现两次,帽子颜色种数最大为 \(\displaystyle cl+\lfloor\frac{cr}{2}\rfloor\).

点击查看代码
#include<bits/stdc++.h>
#define N 100010
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
int n,a[N],mn,mx,cn,cx;
int main(){
	n=read();
	for(int i=1;i<=n;i++)a[i]=read();
	sort(a+1,a+1+n),mn=a[1],mx=a[n];
	if(mn+1<mx)return puts("No"),0;
	if(mn==mx){
		if(mn==n-1||n>=2*mn)puts("Yes");
		else puts("No");
		return 0;
	}
	for(int i=1;i<=n;i++)
		a[i]==mn?cn++:cx++;
	if(mx>=cn+1&&mx<=cn+cx/2)puts("Yes");
	else puts("No");
	
	return 0;
}

C - +/- Rectangle

给定 \(n,m,h,w\),构造一个 \(n\times m\) 的矩阵,满足:

  • 元素权值绝对值 \(\le 10^9\)

  • 矩阵元素权值和为正

  • 任意 \(h\times w\) 的子矩阵元素权值和为负

或报告无解。

\(1\le h\le n\le 500\),\(1\le w\le m\le 500\).


思考无解的情况,发现当且仅当 \(h|n\) 且 \(w|m\),因为可以将其划分为若干 \(h\times w\) 的子矩阵,由于每个子矩阵为负,最后整个矩阵必定为负。

接下来假设 \(h\not|n\),对于编号为 \(h\) 的倍数的行,将其设为负值。

然后随便搞搞即可。只需让最后几个非 \(h\) 的倍数的行把权值和补回来就好了。

对于 \(w\not|m\) 时同理。

点击查看代码
#include<bits/stdc++.h>
#define N 505
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
int n,m,h,w,ans[N][N];
int main(){
	n=read(),m=read(),h=read(),w=read();
	if(n%h==0&&m%w==0)return puts("No"),0;
	if(n%h){
		for(int i=1;i<=n;i++){
			if(i%h){
				for(int j=1;j<=m;j++)
					ans[i][j]=1000000;
			}
			else{
				for(int j=1;j<=m;j++)
					ans[i][j]=-1000000*(h-1)-1;
			}
		}
	}
	else{
		for(int j=1;j<=m;j++){
			if(j%w){
				for(int i=1;i<=n;i++)
					ans[i][j]=1000000;
			}
			else{
				for(int i=1;i<=n;i++)
					ans[i][j]=-1000000*(w-1)-1;
			}
		}
	}
	puts("Yes");
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)
			printf("%d ",ans[i][j]);
		printf("\n");
	}
	
	return 0;
}

D - XOR Replace

给定序列 \(\{a_n\}\),每次可以将一个数变为序列的异或和,问到达 \(\{b_n\}\) 的最小步数。或报告无解。

\(2\le n\le 10^5\),\(0\le a_i,b_i\le 2^{30}\).


不妨视作序列的异或和 \(x\) 放在位置 \(n+1\) 上,每次交换 \(a_i\) 和 \(a_{n+1}\).

容易判断无解。

考虑 \(a_1,a_2,\dots,a_k\Rightarrow a_k,a_1,\dots,a_{k-1}\).

可以从 \(1\) 到 \(k\) 执行 \(\operatorname{swap}(a_i,a_{n+1})\),最后执行 \(\operaotrname{swap}(a_1,a_{n+1})\),一共操作 \(k+1\) 次。

考虑 \(a_1,a_2,\dots,x,\dots,a_k\Rightarrow a_k,a_1,\dots,x,\dots\).

此时从第 \(n+1\) 个数的地方开始交换,会减少一次操作。

对于 \(a_i\not=b_i\),从点 \(a_i\) 向点 \(b_i\) 连一条边。此时答案为 总边数 \(+\) 连通块数 \(-1\).

另外地,当 \(n+1\) 个数不属于任意连通块,此时多减去了 \(1\).

对 \(a_{n+1}\) 和 \(b_{n+1}\) 强制连边,不计入总边数。

使用并查集维护。

点击查看代码
#include<bits/stdc++.h>
#define N 200010
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
int n,a[N],b[N],ta[N],tb[N];
int t[N],tot,len;
int fa[N];
int find(int x){
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x,int y){
	int fx=find(x),fy=find(y);
	if(fx!=fy)fa[fx]=fy;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)
		a[i]=read(),a[n+1]^=a[i];
	for(int i=1;i<=n;i++)
		b[i]=read(),b[n+1]^=b[i];
	n++,memcpy(ta,a,sizeof(a)),memcpy(tb,b,sizeof(b));
	sort(ta+1,ta+1+n),sort(tb+1,tb+1+n);
	for(int i=1;i<n;i++){
		if(ta[i]!=tb[i]){
			puts("-1");
			return 0;
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		if(a[i]!=b[i]||(i==n)){
			t[++tot]=a[i],t[++tot]=b[i];
			if(i<n)ans++;
		}
	}
	if(!ans){
		puts("0");
		return 0;
	}
	sort(t+1,t+1+tot),len=unique(t+1,t+1+tot)-t-1;
	for(int i=1;i<=len;i++)fa[i]=i;
	for(int i=1;i<=n;i++){
		if(a[i]!=b[i]){
			a[i]=lower_bound(t+1,t+1+len,a[i])-t;
			b[i]=lower_bound(t+1,t+1+len,b[i])-t;
			merge(a[i],b[i]);
		}
	}
	for(int i=1;i<=len;i++)
		ans+=(fa[i]==i);
	printf("%d\n",ans-1);
	
	return 0;
}

E - Poor Turkeys

有 \(n\) 只鸡,有 \(m\) 个形如 \((x,y)\) 的操作:

  • 若 \(x\) 和 \(y\) 都活着,等概率吃掉一只。

  • 若 \(x\) 和 \(y\) 恰好活着一只,吃掉剩下的一只。

  • 若 \(x\) 和 \(y\) 均死亡,不进行任何操作。

求有多少个二元组 \((i,j)\) 满足 \(i<j\) 且鸡 \(i\) 和鸡 \(j\) 都可能存活。

\(n\le 400\),\(m\le 10^5\),\(x_i<y_i\).


时光倒流。

记 \(f_{i,j}\) 表示如果要留下 \(i\),是否要炖了 \(j\)。初始 \(f_{i,i}=1\).

如果在某个时刻需要对 \(i,j\) 做抉择,为了留下 \(i\) 一定会炖掉 \(j\),即 \(j\) 在此前应受到和 \(i\) 一样的保护。

考虑鸡 \(i\) 是否能存活。假设有限制 \((i,x)\),\((i,y)\),如果存在限制 \((x,y)\),则 \(i\) 必定死亡。

对于鸡 \(i\),记集合 \(S_i\) 表示让鸡 \(i\) 存活下来需要保护的鸡有哪些,初始 \(S_i=\{i\}\).

从后往前考虑每一对 \((x,y)\),若 \(x,y\in S_i\),\(i\) 必死无疑。若其一 \(\in S_i\),不放设为 \(x\),那么需要保护 \(y\),将 \(y\) 加入 \(S_i\).

对于两只非必死的鸡 \(i,j\),由于一只鸡不能死两次,\((i,j)\) 合法当且仅当 \(S_i\cap S_j=\emptyset\).

时间复杂度 \(O(nm+n^3)\),可以用 bitset 优化为 \(O(nm+\frac{n^3}{\omega})\).

点击查看代码
#include<bits/stdc++.h>
#define N 405
#define M 100010
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
int n,m,x[M],y[M],g[M];
bitset<N>f[N];
int ans;
int main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++)
		x[i]=read(),y[i]=read();
	for(int i=1,u,v;i<=n;i++){
		f[i][i]=true;
		for(int j=m;j;j--){
			u=f[i][x[j]],v=f[i][y[j]];
			if(u&&v)g[i]=true;
			if(u)f[i][y[j]]=true;
			else if(v)f[i][x[j]]=true;
		}
	}
	for(int i=1;i<=n;i++){
		if(g[i])continue;
		for(int j=i+1;j<=n;j++){
			if(g[j])continue;
			ans+=!((f[i]&f[j]).any());
		}
	}
	printf("%d\n",ans);
	
	return 0;
}

F - Games on DAG

给定 \(n\) 个点 \(m\) 条边的 DAG,每条边 \((u,v)\) 满足 \(u<v\).

在 \(1,2\) 号点分别有一颗石头,两人博弈,每次可以沿有向边移动一颗石头,不能移动则输。

问 \(2^m\) 个边的子集中,保留这个子集先手必胜的方案数。答案模 \(10^9+7\).

\(2\le n\le 15\).


即 \(2^m\) 减去所有 \(\operatorname{SG}(1)=\operatorname{SG}(2)\) 的情况。

显然所有点的 SG 值不可能超过 \(n-1\).

对 \(\operatorname{SG}=k\) 的集合,应该在每个 \(\operatorname{SG}<k\) 的集合中选取一个点连边,\(>k\) 的可以任意连。

设 \(S\) 为 \(\operatorname{SG}>k\) 的集合,\(T\) 为 \(\operatorname{SG}=k\) 的集合.

  • 对于 \(S\rightarrow T\) 的边,每个 \(S\) 中的元素至少向 \(T\) 连一条。

  • 对于 \(T\rightarrow S\) 的边,随便连边。

  • 对于 \(T\) 内部,不能连边。

\(1\) 和 \(2\) 应该同时在 \(S\) 或 \(T\) 内。

有 \(O(n\cdot 3^n)\) 的枚举子集做法。

点击查看代码
#include<bits/stdc++.h>
#define N 16
#define M (1<<N)
#define lb(x) x&-x 
#define P 1000000007
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
int n,m;
int cnt[N][M],p2[N*N];
int E[N][N],f[M];
bool check(int T){
	return !!(((T&1)+((T>>1)&1))^1);
}
int main(){
	n=read(),m=read();
	p2[0]=1;
	for(int i=1;i<=m;i++)p2[i]=p2[i-1]*2%P;
	for(int i=1,u,v;i<=m;i++){
		u=read(),v=read();
		E[u][v]++;
	}
	for(int S=0;S<(1<<n);S++)
		for(int i=1;i<=n;i++)
			cnt[i][S]=cnt[i][S^lb(S)]+(!S?0:E[i][(int)log2(lb(S))+1]);
	f[0]=1;
	for(int S=1;S<(1<<n);S++)
		for(int T=S,R,cur;T;T=(T-1)&S){
			R=S^T,cur=1;
			if(!check(T))continue;
			for(int i=1;i<=n;i++){
				if((T>>(i-1))&1)cur=1ll*cur*p2[cnt[i][R]]%P;
				if((R>>(i-1))&1)cur=1ll*cur*(p2[cnt[i][T]]-1)%P;
			}
			(f[S]+=1ll*f[R]*cur%P)%=P;
		}
	printf("%d\n",(p2[m]-f[(1<<n)-1]+P)%P);
	
	return 0;
}

D,E,F 十分有意思。

标签:Atcoder,ch,Contest,int,while,le,016,isdigit,getchar
From: https://www.cnblogs.com/SError0819/p/17809706.html

相关文章

  • AtCoder Beginner Contest 326 (ABC326)
    A.2UP3DOWN直接模拟即可。CodeB.326-likeNumbers枚举,每次拆除百、十、个位,再判断。CodeC.PeakDescription数字线上放置了\(N\)个礼物。第\(i\)个礼物放置在坐标\(A_i\)处。可以在数轴上选择长度为\(M\)的半开区间\([x,x+M)\),并获得其中包含的所有礼物。求:......
  • AtCoder Beginner Contest 224 H Security Camera 2
    洛谷传送门AtCoder传送门直接糊一手线性规划对偶板板。要求:\[\min\sumA_il_i+\sumB_ir_i\]\[\foralli,j,l_i+r_j\geC_{i,j}\]\[l_i,r_i\ge0\]\[l_i,r_i\in\mathbb{Z}\]可以证明\(l_i,r_i\)为整数的限制可以去掉,因为取到最优解时\(l_i,r_i\)一......
  • AtCoder Beginner Contest(abc) 314
    B-Roulette难度:⭐题目大意有一个猜数字的游戏,有n个人参加,每人都猜了若干个数;最后给出答案数字;在所有猜中数字的人中输出猜数数量最少的人的编号;(可能不止一个);解题思路数据不大,暴力即可;神秘代码#include<bits/stdc++.h>#defineintlonglong#def......
  • Oracle ORA-01653:无法在表空间中扩展表
    OracleORA-01653:无法在表空间中扩展表在本文中,我们将介绍Oracle数据库中的一个常见错误,即ORA-01653。该错误是由于无法在表空间中扩展表而引起的。我们将解释该错误的原因,并提供一些解决该问题的示例。阅读更多:Oracle教程什么是ORA-01653错误?ORA-01653错误是Oracle数据库中......
  • P4067 [SDOI2016] 储能表 题解
    [SDOI2016]储能表-洛谷题目详情-[SDOI2016]储能表-BZOJbyHydroOJ一道很好的数位dp题不过这题有一个比较有意思的性质:当\(n,m\)为\(2^k\)的形式时,最终得到的数组对每一行排序后为\(0\simm-1\)的排列,如果有的话说不定可以作为一个部分分?遇到二进制运......
  • asis2016_b00ks(根据报错信息确定mmap拓展偏移)
    这个应该是大部分人学off-by-one的第一个例题,当时笔者也是只在本地去测试,最近重温又发现了一些有趣的东西这里有个off-by-null,可以看到14行如果i=a2就break,再让*a1=0,比如我们的size为10,正常我们被允许输入10个字节的数据,这里的i是从0开始的,所以是0-10,也就是11字节,多出的......
  • AtCoder Beginner Contest 326 F
    F-RobotRotation一句话不开LL,见祖宗感谢大佬,和洛谷上的题解上面已经将的很清楚了,但是如果你跟我一样一开始看不懂他们的代码,那么这篇可能为你解惑点击查看代码#include<bits/stdc++.h>usingnamespacestd;#defineLLlonglong#defineintLL//LL!map<LL,LL>ma;......
  • AtCoder Beginner Contest(abc) 312
    B-TaKCode难度:⭐题目大意题目定义一种矩阵X:该矩阵的是一个长度为9的由黑白色块组成正方形矩阵;该矩阵的左上角和右下角都是一个3*3的黑色矩阵(总共18个),这两个黑色矩阵外面(边缘不算)包围一圈白色色块(总共14个);现在一个n*m的黑白矩阵,问这个大矩阵中有多少......
  • AT_abc326_e Revenge of "The Salary of AtCoder Inc." 题解
    AT_abc326_eRevengeof"TheSalaryofAtCoderInc."题解一道简单的概率论+动态规划题目(然而我赛时没看这道题题意有一个长度为\(n\)的序列\(A\)、一个\(n\)面骰子,掷若干次骰子,如果这一次掷骰子的点数小于等于上一次的点数,则结束。定义这若干次掷骰子的总的结果为,每次......
  • AtCoder Beginner Contest(abc) 311
    B-VacationTogether难度:⭐题目大意给定n个人的工作计划,'o'表示这天休息,'x'表示工作;请找出一段最长的所有人都休息的连续休息的天数;解题思路数据不大,暴力即可;神秘代码#include<bits/stdc++.h>#defineintlonglong#defineIOSios::sync_with_stdio......