Codeforces Round #533 (Div. 2)

Codeforces Round #533 (Div. 2)

打得灰常愉悦的一场CF

如果T1没有fst的话能涨100+额

T1

题意:给出\(n\)个正整数,每个数\(a_i\)可以花费\(|a_i-x|\)的代价变为\(x\)。要求指定一个数\(t\),并变化\(a\)使得所有\(|a_i-t|\le 1\)

由于\(a_i\)的范围很小,暴力枚举\(t\)是什么就行了

当时我写了很假的贪心:我枚举了\(t\)是那个\(a_i\)。。。于是FST了

#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<stack>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline int read(){
	int ans=0,fh=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
		ans=ans*10+ch-'0',ch=getchar();
	return ans*fh;
}
const int maxn=1100;
int n,a[maxn];
int main(){
//	freopen("1.in","r",stdin);
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	int Ans=0x7fffffff,mx=0;
	for(int i=1;i<=100;i++){
		int ans=0;
		for(int j=1;j<=n;j++)
			ans+=max(abs(i-a[j])-1,0);
		if(ans<Ans) Ans=ans,mx=i;
	}
	printf("%d %d\n",mx,Ans);
	return 0;
}

T2

比第一题还水的贪心,模拟一下就好了

#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<stack>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline int read(){
	int ans=0,fh=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
		ans=ans*10+ch-'0',ch=getchar();
	return ans*fh;
}
const int maxn=2e5+100;
int n,k,ans[30];
char s[maxn];
int main(){
//	freopen("1.in","r",stdin);
	n=read(),k=read();
	scanf("%s",s+1);
	int l=1;
	for(int i=2;i<=n;i++)
		if(s[i]!=s[i-1]){
			int len=i-l;
			ans[s[i-1]-'a']+=len/k;
			l=i;
		}
	ans[s[n]-'a']+=(n-l+1)/k;
	int Ans=0;
	for(int i=0;i<26;i++) Ans=max(Ans,ans[i]);
	printf("%d\n",Ans);
	return 0;
}

T3

题意:长度为\(n\)的数组\(a\),每个地方都可以填一个\(l\sim r\)的整数,要求\(\sum_{i=1}^n{a_i}\%3==0\),问有多少种填法

算出每个地方填的数模\(3\)等于\(0,1,2\)的方案数,直接\(dp\)即可,\(f[i][j]\)表示填前\(i\)个,\(\sum_{k=1}^i{a_k}\%3==j\)的方案数

#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<stack>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline int read(){
	int ans=0,fh=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
		ans=ans*10+ch-'0',ch=getchar();
	return ans*fh;
}
const int maxn=2e5+100,P=1e9+7;
int n,l,r;
ll f[maxn][3];
int main(){
	freopen("1.in","r",stdin);
	n=read(),l=read()-1,r=read();
	int a=(r+2)/3-(l+2)/3,b=(r+1)/3-(l+1)/3,c=r/3-l/3;
	f[0][0]=1;
	for(int i=1;i<=n;i++){
		f[i][0]=(f[i-1][1]*b%P+f[i-1][2]*a%P)%P+f[i-1][0]*c%P,f[i][0]%=P;
		f[i][1]=(f[i-1][1]*c%P+f[i-1][2]*b%P)%P+f[i-1][0]*a%P,f[i][1]%=P;
		f[i][2]=(f[i-1][1]*a%P+f[i-1][2]*c%P)%P+f[i-1][0]*b%P,f[i][2]%=P;
	}
	printf("%I64d\n",f[n][0]);
	return 0;
}

T4

题意:一个\(n*m\)的地图,一开始\(p\)个人每人在上面都有一块领土,回合制游戏,每个回合按照人的编号顺序从小到大操作,轮到第\(i\)个人操作时,他可以将自己的领土扩展\(s_i\)次,每次扩展是把所有自己的领土上下左右的所有领土变成自己的(前提是哪里没有障碍),别人占的领土自己就不能占了,问最后每个人分别占了多少领土。

由于地图大小只有\(1000*1000\),直接模拟就好了

\(room\)里有个人扩展的时候判断的是曼哈顿距离(没考虑障碍)被我叉了2333

#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<stack>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<algorithm>
#define mp(x,y) make_pair(x,y)
using namespace std;
typedef long long ll;
inline int read(){
	int ans=0,fh=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
		ans=ans*10+ch-'0',ch=getchar();
	return ans*fh;
}
const int maxn=1e3+100;
queue<pair<int,int> >q[maxn],sxz;
int n,m,p,a[maxn],d[maxn][maxn],ans[maxn];
int uu[4]={1,0,-1,0};
int vv[4]={0,-1,0,1};
char s[maxn];
inline bool check(){
	for(int i=1;i<=p;i++) if(!q[i].empty()) return 0;
	return 1;
}
int main(){
//	freopen("1.in","r",stdin);
	n=read(),m=read(),p=read();
	for(int i=1;i<=p;i++) a[i]=read();
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++)
			if(s[j]=='#') d[i][j]=-1;
			else{
				if(s[j]!='.'){
					int x=d[i][j]=s[j]-'0';
					q[x].push(mp(i,j));
				} 
			}
	}
	while(!check()){
		for(int i=1;i<=p;i++){
			for(int j=1;j<=a[i];j++){
				if(q[i].empty()) break;
				while(!q[i].empty()){
					pair<int,int> zhy=q[i].front();q[i].pop();
					int x=zhy.first,y=zhy.second;
					for(int k=0;k<4;k++){
						int vx=x+uu[k],vy=y+vv[k];
						if(vx<1||vx>n||vy<1||vy>m||d[vx][vy]) continue;
						d[vx][vy]=i;
						sxz.push(mp(vx,vy));
					}
				}
				while(!sxz.empty()) q[i].push(sxz.front()),sxz.pop();
			}
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(d[i][j]!=-1) ans[d[i][j]]++;
	for(int i=1;i<=p;i++) printf("%d ",ans[i]);
	printf("\n");
	return 0;
}

T5

题意:你有\(m\)个朋友,这些朋友会按顺序去拜访你,每个朋友都有一个互不相同的喜欢的名字,如果他去拜访你的时候你恰好叫这个名字,他就会很高兴(???),你可以在特定时间去改你的名字,问你可以最多让几个朋友一直高兴。

比赛时想到了转化成图求最大点独立集,\(sxz\)大佬想到了\(meet-in-the-middle\),然而最后还是没想到正解

正解就是先让一组拜访的朋友两两之间连边,转化成图,然后用\(meet-in-the-middle\)的思想,分别处理出前\(n/2\)个点和后\(n-n/2\)个点选集合\(a_i\)时的最大点独立集大小,最后把他们合起来就好了

合起来的方法:枚举前一个集合,求出在满足不与前一个集合有连边的最大的后一个集合,答案就是两个集合的答案加起来去最值

#include <cstdio>
#include <cstring>
#include <queue>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
using namespace std;
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(S==T) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=1<<21,maxt=110;
int n,m,ans,Tot,cz[maxn];
bool mp[maxt][maxt];
string pp[maxt],zhy;
int f1[maxn],f2[maxn];
map<string,int>mmp;
inline void work(){
	int s1=n>>1,s2=n-s1;
	for(int i=0;i<s1;i++) f1[1<<i]=1;
	for(int i=0,lim=1<<s1;i<lim;i++){
		for(int j=0;j<s1;j++)
			if(!(i>>j&1)){
				int ok=1;
				for(int k=0;k<s1;k++)
					if(i>>k&1)
						ok&=mp[j+1][k+1];
				f1[i|1<<j]=max(f1[i|1<<j],f1[i]+ok);
			}
	}
	for(int i=0;i<s2;i++) f2[1<<i]=1;
	for(int i=0,lim=1<<s2;i<lim;i++){
		for(int j=0;j<s2;j++)
			if(!(i>>j&1)){
				int ok=1;
				for(int k=0;k<s2;k++)
					if(i>>k&1)
						ok&=mp[s1+j+1][s1+k+1];
				f2[i|1<<j]=max(f2[i|1<<j],f2[i]+ok);
			}
	}
	int ans=0;
	for(int i=0,lim=1<<s1;i<lim;i++){
		int nw=(1<<s2)-1;
		for(int j=0;j<s1;j++)
			if(i>>j&1){
				for(int k=0;k<s2;k++)
					if(!mp[j+1][s1+k+1]) nw&=((1<<s2)-1)^(1<<k);
			}
		ans=max(ans,f1[i]+f2[nw]);
	}
	printf("%d\n",ans);
}
int main(){
//    freopen("1.in","r",stdin);
    int nn=read(),mm=read();
    memset(mp,1,sizeof(mp));
    for(int i=1;i<=nn;i++){
    	int ms=read();
    	if(ms==1){
    		int cnt=0;
    		for(int j=1;j<=mm;j++)
    			for(int k=1;k<=mm;k++)
    				if(cz[j]&&cz[k]&&j!=k)
    					mp[j][k]=mp[k][j]=0;
    		for(int j=1;j<=mm;j++) cz[j]=0;
		}
		else{
			cin>>zhy;
			if(!mmp[zhy]) mmp[zhy]=++Tot;
			int sxz=mmp[zhy];
			cz[sxz]=1;
		}
	}
	for(int j=1;j<=mm;j++)
		for(int k=1;k<=mm;k++)
			if(cz[j]&&cz[k]&&j!=k)
				mp[j][k]=mp[k][j]=0;
	n=mm,work();
    return 0;
}
posted @ 2019-01-21 09:35  nianheng  阅读(219)  评论(0编辑  收藏  举报