Codeforces Round #584 - Dasha Code Championship - Elimination Round (rated, open for everyone, Div. 1 + Div. 2) 题解
A.Paint the Numbers
题目大意
给定 N N N个数的数列 A A A,若当 A i ≡ 0 ( m o d    A j ) A_i\equiv 0(\mod A_j) Ai≡0(modAj),则 A i A_i Ai和 A j A_j Aj可以分到同一类,求最少有多少类。
分析
水题,暴力模拟即可。
参考代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int Maxn=100;
int N,A[Maxn+5];
bool vis[Maxn+5];
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
scanf("%d",&N);
for(int i=1;i<=N;i++)
scanf("%d",&A[i]);
sort(A+1,A+N+1);
for(int i=1;i<=N;i++)
if(!vis[i])
for(int j=i+1;j<=N;j++)
if(A[j]%A[i]==0)vis[j]=true;
int cnt=0;
for(int i=1;i<=N;i++)
if(!vis[i])cnt++;
printf("%d\n",cnt);
return 0;
}
B.Koala and Lights
题目大意
对于 N N N盏灯,每盏灯有两个属性 a i , b i a_i,b_i ai,bi,表示第 i i i盏灯从零时刻开始在 b i b_i bi时刻变一次(由开到关或由关到开),此后每隔 a i a_i ai秒变化一次。求最多有多少盏灯是打开的。
分析
我TM比赛时想了一个多小时才想出来QAQ…(脑子进水了。。。
通过一波证明可以发现最多125秒后就会出现循环。。。(我实在不会证明,有人会证的话请在评论区补一下 :-)
参考代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Maxn=100;
const int M=100000;
int N,A[Maxn+5],B[Maxn+5];
int f[Maxn+5];
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
char s[Maxn+5];
scanf("%d %s",&N,s+1);
for(int i=1;i<=N;i++)
scanf("%d %d",&A[i],&B[i]);
int ans=0;
for(int i=1;i<=N;i++) {
f[i]=s[i]-'0';
ans+=f[i];
}
for(int tim=1;tim<=M;tim++) {
for(int i=1;i<=N;i++)
if(tim>=B[i]&&(tim-B[i])%A[i]==0)
f[i]=(!f[i]);
int tmp=0;
for(int i=1;i<=N;i++)
tmp+=f[i];
ans=max(ans,tmp);
}
printf("%d\n",ans);
return 0;
}
C.Paint the Digits
题目大意
将一个由数字0
到9
组成的字符串分成两部分,要求将第一部分的所有数按顺序取出来之后接上第二部分的所有按顺序取出的数,若能够形成一个最长不下降子序列则输出一个方案,否则输出-
。
分析
参考代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Maxn=2e5;
int N;
char s[Maxn+5],s1[Maxn+5];
bool vis[Maxn+5];
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int _;
scanf("%d",&_);
while(_--) {
scanf("%d %s",&N,s);
memcpy(s1,s,sizeof s);
memset(vis,false,sizeof vis);
sort(s1,s1+N);
char mn=255;int pos=0;
for(int i=0;i<N;i++)
if(mn>s[i])
mn=s[i],pos=i;
int len=0;
for(int i=pos;i<N;i++)
if(s1[len]==s[i])
vis[i]=true,++len;
bool flag=true;
for(int i=0;i<N;i++)
if(!vis[i]) {
if(s[i]!=s1[len]) {
flag=false;
break;
}
len++;
}
if(!flag) {
puts("-");
continue;
}
for(int i=0;i<N;i++)
putchar(vis[i]?'1':'2');
puts("");
}
return 0;
}
D.Cow and Snacks
题目大意
有 K K K个人分享 N N N种零食,每个人有两种喜欢的零食。现在将所有人排成一排,一个人拿着 N N N种零食从前往后走,每个人会吃掉他所喜欢的所有零食,若一种也没吃掉就很沮丧。求最少的沮丧的人数。
分析
考虑将每个人所喜欢的零食连起来,这样问题就变成了一个图论问题。
对于一个含有 c c c个点的连通块,我们可以发现它最多可以满足 c − 1 c-1 c−1个人。
那么我们记 C C C为连通块的个数, n n n为出现的零食的个数,则答案为 K − n + C K-n+C K−n+C。
参考代码
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int Maxn=1e5;
vector<int> G[Maxn+5];
inline void addedge(int u,int v) {
G[u].push_back(v),G[v].push_back(u);
}
int N,K;
bool vis[Maxn+5],used[Maxn+5];
void DFS(int u) {
vis[u]=true;
for(int i=0;i<(int)G[u].size();i++)
if(!vis[G[u][i]])DFS(G[u][i]);
}
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
scanf("%d %d",&N,&K);
int cnt=0;
for(int i=1;i<=K;i++) {
int x,y;
scanf("%d %d",&x,&y);
addedge(x,y);
if(!used[x])cnt++;
if(!used[y])cnt++;
used[x]=used[y]=true;
}
int ans=0;
for(int i=1;i<=N;i++)
if(used[i]&&!vis[i])
DFS(i),ans++;
printf("%d\n",K-cnt+ans);
return 0;
}
E1.Rotate Columns (easy version)
题目大意
给定一个 N × M N\times M N×M的矩阵,你可以对每一列的数字进行任意次的旋转操作(即整体向上或者整体向下)。输出在做出任意次旋转操作后每一行的最大值之和。
分析
考虑到 N N N很小,我们用状压DP解决。
设状态 f ( i , S ) f(i,S) f(i,S)为当前在对第 i i i列进行旋转操作,对于 S S S中的行已经计算出答案的情况。
对于每一列,我们暴力旋转 N N N次,每次暴力转移即可。
参考代码
用E2的代码就可以了。
可以去掉这个排序的部分。
E2.Rotate Columns (hard version)
题目大意
同E1,只是数据范围更大。
分析
在E1的基础上,我们考虑贪心。
显然我们可以用每列上的最大值来比较每一列,这样的话我们只需要转这几列即可。
具体还是看代码吧。。。
参考代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Maxn=12;
const int Maxm=2000;
int N,M;
int A[Maxn+5][Maxm+5];
struct Node {
int key,id;
};
bool operator < (Node lhs,Node rhs){return lhs.key>rhs.key;}
Node t[Maxm+5];
int f[(1<<Maxn)+5],t1[(1<<Maxn)+5],t2[(1<<Maxn)+5];
bool used[Maxm+5];
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int _;
scanf("%d",&_);
while(_--) {
scanf("%d %d",&N,&M);
for(int i=1;i<=M;i++)
t[i].id=i,t[i].key=0,used[i]=false;
for(int i=0;i<N;i++)
for(int j=1;j<=M;j++) {
scanf("%d",&A[i][j]);
t[j].key=max(t[j].key,A[i][j]);
}
sort(t+1,t+M+1);
for(int i=1;i<=M&&i<=N;i++)
used[t[i].id]=true;
memset(f,0,sizeof f);
for(int i=1;i<=M;i++) {
if(!used[i])continue;
for(int s=0;s<(1<<N);s++)
t1[s]=0;
for(int j=1;j<=N;j++) {
for(int s=0;s<(1<<N);s++)
t2[s]=f[s];
for(int s=0;s<(1<<N);s++)
for(int k=0;k<N;k++)
if(!(s&(1<<k)))
t2[s|(1<<k)]=max(t2[s|(1<<k)],t2[s]+A[k][i]);
int tmp=A[0][i];
for(int k=0;k<N-1;k++)
A[k][i]=A[k+1][i];
A[N-1][i]=tmp;
for(int s=0;s<(1<<N);s++)
t1[s]=max(t1[s],t2[s]),t2[s]=0;
}
for(int s=0;s<(1<<N);s++)f[s]=t1[s];
}
printf("%d\n",f[(1<<N)-1]);
}
return 0;
}