Codeforces Round #533 (Div. 2)
Codeforces Round #533 (Div. 2)
- 链接:Codeforces
打得灰常愉悦的一场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;
}