Codeforces Round #533 (Div. 2)比赛总结

在第一次CF第一题被叉与第二次CF第一题被FST掉的阴影下,报名参加了第三次的CF。。。心路历程大概是这样的:

开场后15min内:wocCF怎么上不上去?。。。算了到CF群里开始看起了T1题面,慌乱之中又看漏了T1中的正整数,成功掉了50分。。。

终于在21min过了T1,开始看T2

1min后:嗯这道题怎么好像很简单啊。。。4min左右写完,然后网卡,交不了。。。

然后大概在26min左右看起了T3:这道题不是傻逼DP吗?写完把细节改了改,35min左右过了所有样例,然而。。。woc怎么还是交不了?

于是看起T4。。。到了41min,啊终于能交了,于是在41min同时过了T2与T3

剩下的2h-41min=1h19min:一直T4BFS不会写,非要写BFS套BFS还傻逼地以为写的非常是正解,看到TLE后还加了一个类似分层图的优化更加觉得是正解了,但这并不妨碍我从头T到尾。。。

然后、、比赛结束,以rank1300多强势垫底


认真地总结一下吧:CF每次都发挥不出水平,主要是因为CF的按时间减分的赛制让我每次都非常紧张,迫切地想把每一题都迅速做完,然后每题就不敢多想,自然也就不能发挥出来了。所以既然考场上没来得及想,就在考完试后再多想想吧。其次的话,自己水平还是不行吧,如果水平够的话也不会那么紧张,所以还是需要多加训练。话不多说,开始说题


A. Salem and Sticks

暴力枚举,三种情况取个min即可

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
using namespace std;
const int N=1e3+10;
const int INF=1e9;
int n,a[N],t,ans=INF;
int main(){
	scanf("%d",&n);
	for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(register int p=1;p<=100;p++){
		int sum=0;
		for(register int i=1;i<=n;i++)
			sum+=min(abs(a[i]-p),min(abs(a[i]-1-p),abs(a[i]+1-p)));
		if(sum<ans)ans=sum,t=p;
	}
	printf("%d %d\n",t,ans);
	return 0;
}

B. Zuhair and Strings

还是暴力枚举

#include<cstdio>
#include<iostream>
using namespace std;
const int N=2e5+10;
int n,k,sum,ans,now;
char s[N];
int main(){
	scanf("%d%d",&n,&k);
	scanf("%s",s+1);
	for(register int i=0;i<26;i++){
		sum=now=0;
		for(register int j=1;j<=n;j++){
			if(s[j]==i+'a')now++;else now=0;
			if(now==k)sum++,now=0;
		}
		ans=max(ans,sum);
	}
	printf("%d\n",ans);
	return 0;
}

C. Ayoub and Lost Array

\(dp[i][j]\)表示前 \(i\) 个数和在模 \(3\) 意义下为 \(j\) 的方案数,然后枚举 \(l,r\) 转移,复杂度 \(O(3n(r-l))\)

考虑把 \(l-r\) 中的数放在模 \(3\) 的剩余系下处理,这样复杂度就只有 \(O(9n)\)

#include<cstdio>
#include<iostream>
using namespace std;
const int N=2e5+10;
const int mod=1e9+7;
int n,l,r,dp[N][3],num[3];
inline void Add(int &x,int y){x+=y;x-=x>=mod? mod:0;}
int main(){
	scanf("%d%d%d",&n,&l,&r);
	num[0]=r/3+1;
	if(r-1>=0)num[1]=(r-1)/3+1;
	if(r-2>=0)num[2]=(r-2)/3+1;
	if(l-1>=0)num[0]-=max((l-1)/3+1,0);
	if(l-2>=0)num[1]-=max((l-2)/3+1,0);
	if(l-3>=0)num[2]-=max((l-3)/3+1,0);
	dp[0][0]=1;
	for(register int i=1;i<=n;i++)
		for(register int j=0;j<3;j++)
			for(register int p=0;p<3;p++)
				Add(dp[i][j],1ll*dp[i-1][(j-p+3)%3]*num[p]%mod);
	printf("%d\n",dp[n][0]);
	return 0;
}

D. Kilani and the Game

也就是个简单的BFS,注意访问过的点直接打上vis标记不再访问即可

同一种颜色的点同时BFS,不要每个单独BFS(我当时就是这样T掉的)

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=1e3+10;
const int M=20;
int n,m,p,s[N],head[M],cnt,num[N][N],ans[M];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool vis[N][N];
char mp[N][N];
struct peo{int nxt,x,y;}P[N*N];
struct node{int lef,x,y,col;node(int leff=0,int xx=0,int yy=0,int coll=0){lef=leff;x=xx;y=yy;col=coll;}};
queue<node>q;
inline void Add(int po,int x,int y){P[++cnt].nxt=head[po];P[cnt].x=x;P[cnt].y=y;head[po]=cnt;}
inline void exBFS(node k){
	queue<node>nq;nq.push(k);
	while(!q.empty()&&q.front().col==k.col)nq.push(q.front()),vis[q.front().x][q.front().y]=true,q.pop();
	vis[k.x][k.y]=true;
	while(!nq.empty()){
		node u=nq.front();nq.pop();
		for(register int i=0;i<4;i++){
			int nx=u.x+dx[i],ny=u.y+dy[i];
			if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&mp[nx][ny]!='#'&&(num[nx][ny]==0||num[nx][ny]==u.col)){
				num[nx][ny]=u.col;
				if(!vis[nx][ny]){
					vis[nx][ny]=true;
					if(u.lef>1)nq.push(node(u.lef-1,nx,ny,u.col));
					else q.push(node(s[u.col],nx,ny,u.col));
				}
			}
		}
	}
}
inline void BFS(){
	while(!q.empty()){node u=q.front();q.pop();exBFS(u);}
}
int main(){
	scanf("%d%d%d",&n,&m,&p);
	for(register int i=1;i<=p;i++)scanf("%d",&s[i]);
	for(register int i=1;i<=n;i++)scanf("%s",mp[i]+1);
	for(register int i=1;i<=n;i++)
		for(register int j=1;j<=m;j++)
			if(mp[i][j]!='#'&&mp[i][j]!='.')
				Add(mp[i][j]-'0',i,j),num[i][j]=mp[i][j]-'0';
	for(register int i=1;i<=p;i++)
		for(register int j=head[i];j;j=P[j].nxt)
			q.push(node(s[i],P[j].x,P[j].y,i)),vis[P[j].x][P[j].y]=true;
	BFS();
	for(register int i=1;i<=n;i++)
		for(register int j=1;j<=m;j++)
			ans[num[i][j]]++;
	for(register int i=1;i<=p;i++)
		printf("%d%c",ans[i],i==p? '\n':' ');
	return 0;
}

E. Helping Hiasat

因为一个组中的人一定是相互排斥的,所以在一个组中的人中两两建边,表示这两个人不能同时选,然后建出来的图的最大独立集的点数就是最多的愉悦人数。

那么怎么求无向图的最大独立集呢?有一个性质:一个无向图的最大独立集等于这个无向图补图的最大团。

这个性质可以这么理解:对于原图,如果两个点之间有边,那么在补图中一定没有这条边,而最大团要求所选取的点集中的点两两都有边相连,那么这两个点就不可能同在补图的最大团中,也就相应的不可能同在原图的最大独立集中了

然后最大团的话,多随机几下加点顺序取个最大值就行了

#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<bitset>
#include<algorithm>
using namespace std;
const int N=50;
int n,m,k,store[N],a[N],tot,T=5e4;
bool Walk[N][N];
string s;
map<string,int>mp;
bitset<N>sav,ans;
inline void Process1(){
	for(register int i=1;i<=store[0];i++)
		for(register int j=i+1;j<=store[0];j++)
			Walk[store[i]][store[j]]=Walk[store[j]][store[i]]=false;
	memset(store,0,sizeof(store));
}
inline void Process2(){
	if(!mp.count(s))mp[s]=++tot;
	store[++store[0]]=mp[s];
}
int main(){
	scanf("%d%d",&n,&m);scanf("%d",&k);n--;
	memset(Walk,true,sizeof(Walk));
	while(n--){
		scanf("%d",&k);
		if(k==1)Process1();
		else cin>>s,Process2();
	}
	Process1();
	for(register int i=1;i<=m;i++)a[i]=i;
	while(T--){
		random_shuffle(a+1,a+m+1);
		for(register int i=1;i<=m;i++)sav[i]=1;
		for(register int i=1;i<=m;i++)
			if(sav[a[i]]==1)
				for(register int j=i+1;j<=m;j++)
					if(!Walk[a[i]][a[j]])sav[a[j]]=0;
		if(sav.count()>ans.count())ans=sav;
	}
	printf("%d\n",ans.count());
	return 0;
}

1月31号的codeforces再战!(立flag:下次一定要到深蓝)

posted @ 2019-01-20 23:19  ForwardFuture  阅读(663)  评论(4编辑  收藏  举报