Codeforces Round #639 (Div. 1) A~C
A. Hilbert's Hotel
题意:给定长为n(2e5)的序列ai,对于所有整数k(-oo ~ +oo),将其变为k+a(k%n),问经过此变化后是否会有两个数字变成同一个数字。
思路:i+kn在进行变化后仍然相差kn,即%n得到的数字相同。不妨以0~n-1这n个数字作为代表,如果得到的数字中有%n相同的,那么一定可以通过对原数字+kn使得二者变化后相同,如果没有则无论原数字如何变化都不能使得二者变化后相同。所以只需要判断0~n-1进行变化后%n是否有相同的数字即可。
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define dl double 4 void rd(int &x){ 5 x=0;int f=1;char ch=getchar(); 6 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 7 while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f; 8 } 9 void lrd(LL &x){ 10 x=0;int f=1;char ch=getchar(); 11 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f; 13 } 14 const int INF=1e9; 15 const LL LINF=1e18; 16 const int N=2e5+10; 17 using namespace std; 18 int T; 19 int n,a[N]; 20 int main(){ 21 // freopen("in.txt","r",stdin); 22 rd(T); 23 while(T--){ 24 rd(n);for(int i=0;i<n;i++)rd(a[i]); 25 for(int i=0;i<n;i++)a[i]=((i+a[i])%n+n)%n; 26 sort(a,a+n);bool flg=0; 27 for(int i=0;i<n-1;i++)if(a[i] == a[i+1])flg=1; 28 if(flg)printf("NO\n");else printf("YES\n"); 29 } 30 return 0; 31 } 32 /**/
B. Monopole Magnets
题意:有两种磁石,N和S,给一个n*m(1e3 * 1e3)的黑白方格,你可以任意的往一些位置上放上S使得每一行和每一列至少有一个S。当N和S在同一行或者同一列且不在一个格子的时候,N可以向S的方向移动一格。问最少需要几个N使得所有的黑格都可以被N遍历到而所有的白格都不能被N遍历到。不合法输出-1。
思路:考虑一行中存在黑白黑这样的格子,那么无论这一行的S放到哪里,总会将本在黑的N吸引到白格子处。所以白格子必须以前缀或者后缀的形式出现。行和列都是如此,于是可以判断出-1的一种情况。而如果有一行全是白格子,但却没有一列全是白格子,那么无论将S放到这一行的哪个位置,总会将其对应列黑格子中的N吸引过来,于是不存在合法情况,列同理。而当既有空白行又有空白列的时候,我们可以将它们的交界处放上S,它们不会吸引任何的N,同时也保证了纯白行列至少具有一个S。进而我们可以在所有黑格子上放上S,也不会出现将N吸引至白格的情况,N可以在黑格子中任意上下左右移动,于是只需要判断有几个联通的黑格子块,bfs即可。
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define dl double 4 void rd(int &x){ 5 x=0;int f=1;char ch=getchar(); 6 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 7 while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f; 8 } 9 void lrd(LL &x){ 10 x=0;int f=1;char ch=getchar(); 11 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f; 13 } 14 const int INF=1e9; 15 const LL LINF=1e18; 16 const int N=1005; 17 using namespace std; 18 int n,m; 19 char s[N]; 20 int a[N][N]; 21 bool vis[N][N]; 22 int cnt; 23 int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1}; 24 void dfs(int x,int y){ 25 vis[x][y]=1; 26 for(int i=0;i<4;i++){ 27 int tx=x+dx[i],ty=y+dy[i]; 28 if(a[tx][ty] && (!vis[tx][ty]))dfs(tx,ty); 29 } 30 } 31 void work(){ 32 int cnt1=0,cnt2=0; 33 for(int i=1;i<=n;i++){ 34 int id1=m+1,id2=0; 35 for(int j=1;j<=m;j++)if(a[i][j]){id1=j;break;} 36 for(int j=m;j>=1;j--)if(a[i][j]){id2=j;break;} 37 if(!id2)cnt1++; 38 for(int j=id1;j<=id2;j++) 39 if(!a[i][j]){printf("-1\n");return ;} 40 } 41 for(int j=1;j<=m;j++){ 42 int id1=n+1,id2=0; 43 for(int i=1;i<=n;i++)if(a[i][j]){id1=i;break;} 44 for(int i=n;i>=1;i--)if(a[i][j]){id2=i;break;} 45 if(!id2)cnt2++; 46 for(int i=id1;i<=id2;i++) 47 if(!a[i][j]){printf("-1\n");return ;} 48 } 49 if(cnt1 && (!cnt2)){printf("-1\n");return ;} 50 if(cnt2 && (!cnt1)){printf("-1\n");return ;} 51 for(int i=1;i<=n;i++) 52 for(int j=1;j<=m;j++) 53 if(!vis[i][j] && a[i][j]){cnt++;dfs(i,j);} 54 printf("%d\n",cnt); 55 } 56 int main(){ 57 // freopen("in.txt","r",stdin); 58 rd(n);rd(m); 59 for(int i=1;i<=n;i++){ 60 scanf("%s",s+1); 61 for(int j=1;j<=m;j++)if(s[j] == '#')a[i][j]=1; 62 } 63 work(); 64 return 0; 65 } 66 /**/
C. Quantifier Question
题意:定义f(x1,x2,...,xn)=(x_j1 < x_k1) && (x_j2 < x_k2) && ... && (x_jn < x_kn)。Q_xi表示任意xi或者存在xi。有n(2e5)个xi,输入m(2e5)对关系ji,ki。寻找一个Q_x1,Q_x2,Q_x3,...,Q_xn使得f(x1,x2,...,xn)为真。注意逻辑词的顺序不能发生变化。如"任意x1使得存在x2使得任意x3满足f为真"与"任意x1使得任意x2使得存在x3满足f为真"是不同的。如果有多种方案则需要使得"存在"使用的最少。输出方案,不存在输出-1。
思路:考虑对于一个小于关系,进行一条连边。如果xi<xj则连i->j的单向边。如果建出来的图没有环,则一定有合法情况,即可以将所有的Q取"存在"。如果有环则不合法。从x1开始考虑,如果其取"存在",则从其开始可以遍历到的点以及可以遍历到它的点,都不能取"任意",因为与其存在大小关系的联系。而如果x1取"任意",情况是相同的,即它能遍历到的和能遍历到它的点都只能取"存在"。所以我们贪心的取"任意"。于是继续考虑x2,如果它从来没有被之前的点遍历到,那么它不受任何约束,同x1可以贪心的取"任意",而如果它被遍历到过,那么它只能取"存在",并且他能遍历到的点和能遍历到它的点也不再能取"任意"了,因为与其存在大小关系。我们可以建两张图来实现这个过程,一张图正向建边,另一张图反向建边,遍历的时候通过vis标记可以使得最终复杂度是O(n)。
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define dl double 4 void rd(int &x){ 5 x=0;int f=1;char ch=getchar(); 6 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 7 while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f; 8 } 9 void lrd(LL &x){ 10 x=0;int f=1;char ch=getchar(); 11 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f; 13 } 14 const int INF=1e9; 15 const LL LINF=1e18; 16 const int N=2e5+10; 17 using namespace std; 18 int n,m; 19 vector<int>a[N]; 20 vector<int>b[N]; 21 int in[N]; 22 queue<int>S; 23 void check(){ 24 for(int i=1;i<=n;i++)if(!in[i])S.push(i); 25 while(!S.empty()){ 26 int u=S.front();S.pop(); 27 for(int i=0;i<a[u].size();i++) 28 if(!(--in[a[u][i]]))S.push(a[u][i]); 29 } 30 for(int i=1;i<=n;i++)if(in[i]){printf("-1\n");exit(0);} 31 } 32 int ans[N]; 33 bool vis[N][3]; 34 void dfs1(int x){ 35 vis[x][1]=1; 36 for(int i=0;i<a[x].size();i++) 37 if(!vis[a[x][i]][1])dfs1(a[x][i]); 38 } 39 void dfs2(int x){ 40 vis[x][2]=1; 41 for(int i=0;i<b[x].size();i++) 42 if(!vis[b[x][i]][2])dfs2(b[x][i]); 43 } 44 int main(){ 45 // freopen("in.txt","r",stdin); 46 rd(n);rd(m); 47 for(int i=1;i<=m;i++){ 48 int x,y;rd(x);rd(y); 49 a[x].push_back(y); 50 b[y].push_back(x); 51 in[y]++; 52 } 53 check(); 54 int cnt=0; 55 for(int i=1;i<=n;i++){ 56 if((!vis[i][1]) && (!vis[i][2]))cnt++,ans[i]=1; 57 if(!vis[i][1])dfs1(i); 58 if(!vis[i][2])dfs2(i); 59 } 60 printf("%d\n",cnt); 61 for(int i=1;i<=n;i++)if(ans[i])putchar('A');else putchar('E'); 62 return 0; 63 } 64 /**/