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 /**/
View Code

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 /**/
View Code

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 /**/
View Code

 

posted @ 2020-05-10 22:43  hyghb  阅读(179)  评论(0编辑  收藏  举报