题解 Codeforces Round #616 (Div. 2) (CF1291)

A:整个串数字和%2==0,末尾%2==1,不就是挑出来两个奇数吗。。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define it register int
 4 #define ct const int
 5 #define il inline
 6 const int N=100005;
 7 int T,n,s,o[N],cnt;
 8 char a[N];
 9 int main(){
10     scanf("%d",&T);it i;
11     while(T--){
12         scanf("%d%s",&n,a+1),cnt=0;
13         for(i=1;cnt<2&&i<=n;++i)
14             if((a[i]-'0')&1) o[++cnt]=i;
15         if(cnt<2) puts("-1");
16         else printf("%c%c\n",a[o[1]],a[o[2]]);
17     }
18     return 0;
19 }
CF1291A

B:由于只能变小不能变大,所以单升的必须满足a[i]>=i-1,单降的满足a[i]>=n-i。从前往后扫找到第一个不满足a[i]>=i-1的,那么它的前面都是满足单调升的。从后往前找第一个不满足a[i]>=n-i的,那么它的后面都是满足单调减的。如果有交集说明有解,否则无解。

 1 #include<stdio.h>
 2 #define it register int
 3 #define ct const int 
 4 #define il inline
 5 const int N=1000005;
 6 int T,n,a[N];
 7 int main(){
 8     scanf("%d",&T);it i;
 9     while(T--){
10         scanf("%d",&n);
11         register bool fl=1;int pos1=0,pos2=0;
12         for(i=1;i<=n;++i){
13             scanf("%d",&a[i]);
14             if(!pos1&&a[i]<i-1) pos1=i-1;
15         }
16         if(!pos1) pos1=n;
17         for(i=n;i;--i) if(a[i]<(n-i)){pos2=i+1;break;}
18         if(!pos2) pos2=1;
19         pos2>pos1?puts("No"):puts("Yes");
20     }
21     return 0;
22 }
CF1291B

C:窝刚了一个半小时,真棒!一共试了三种算法,最后还是写的暴力。。

枚举一下现在强制多少人从左边拿,遍历剩下不听他的人的人数,然后把从后往前和从前往后的最大值的最小值的最大值算出来就可以了。

upd:开始有一些用词不当,经本校学弟@DFTMR指正已经修改。(窝好像次次C题的题解都能被揪出毛病来。。)

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<algorithm>
 5 #define it register int
 6 #define ct const int
 7 #define il inline
 8 using namespace std;
 9 const int N=100005;
10 int ans,o,T,n,m,k,a[N];
11 il int Min(ct p,ct q){return p<q?p:q;}
12 il int Max(ct p,ct q){return p>q?p:q;}
13 namespace io{
14     il char nc(){
15         static char buf[100000],*p1=buf,*p2=buf;
16         return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 
17     }
18     template <class I> 
19     il void fr(I &num){
20         num=0;register char c=nc();it p=1;
21         while(c<'0'||c>'9') c=='-'?p=-1,c=nc():c=nc();
22         while(c>='0'&&c<='9') num=num*10+c-'0',c=nc();
23         num*=p;
24     } 
25 }
26 using io ::fr;
27 int main(){
28     fr(T);it i,j;
29     while(T--){
30         fr(n),fr(m),fr(k),ans=-2e9,k=Min(k,m-1);//最多控制前m-1个多了没用
31         for(i=0;i<n;++i) fr(a[i]);
32         for(i=0;i<=k;ans=Max(ans,o),i++)//枚举控制人数
33             for(j=0,o=2e9;j<m-k;j++) 
34                 o=Min(o,Max(a[i+j],a[n+i+j-m]));//n-(m-k-1-j)-(k-i)-1 就是算从前往后与从后往前的最大值的最小值
35         printf("%d\n",ans);
36     }
37     return 0;
38 }
CF1291C

D:一堆区间不强制在线显然上莫队。首先对于l==r的肯定是yes,然后对于有3种及以上字符的也是yes,如果首尾不同只要把尾放首首放尾肯定是yes,一种字符肯定是no。剩下两种字符首尾相同的就是no了。真·结论题(虽然我ABD用的时间加一起还没C多。。)

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<algorithm>
 5 #define it register int
 6 #define ct const int
 7 #define il inline
 8 using namespace std;
 9 const int N=1000005;
10 struct ky{
11     int l,r,x,id;
12 }a[N];
13 int n,m,bk,k,l,r,b[N],ans,s[N],o1[N];
14 char S[N];
15 bool cmp(ky a,ky b){
16     return a.x^b.x?a.l<b.l:((a.x&1)?a.r<b.r:a.r>b.r);
17 } 
18 int main(){
19     scanf("%s",S+1),n=strlen(S+1);
20     for(it i=1;i<=n;++i) b[i]=S[i]-'a'+1;
21     it bk=sqrt(n),i;
22     scanf("%d",&m);
23     for(i=1;i<=m;i++)
24         scanf("%d%d",&a[i].l,&a[i].r),a[i].x=a[i].l/bk,a[i].id=i;
25     sort(a+1,a+1+m,cmp);
26     l=1,r=0;
27     for(i=1;i<=m;i++){
28         if(a[i].l==a[i].r){o1[a[i].id]=1;continue;}
29         while(l<a[i].l) ans-=(!--s[b[l++]]);
30         while(l>a[i].l) ans+=(!s[b[--l]]++);
31         while(r<a[i].r) ans+=(!s[b[++r]]++);
32         while(r>a[i].r) ans-=(!--s[b[r--]]);
33         o1[a[i].id]=((ans==2&&b[a[i].l]!=b[a[i].r]||ans>2)?1:-1);
34     }
35     for(i=1;i<=m;i++)
36         o1[i]==-1?puts("No"):puts("Yes");
37     return 0;
38 }
CF1291D

E:先鸽着

F:同E

先把cf官方题解搬来吧(虽然我觉得EF都挺可做的)

抱歉复制过来公式挂了将就着看吧。。

 

1290C - Prefix Enlightenment

 

The condition "the intersection of any three subsets is empty" can be easily rephrased in a more useful way: each element appears in at most two subsets.

Let's suppose for the moment that each elements appears in exactly two subsets. We can think of each element as an edge between the subsets, it's a classical point of view. If we see subsets as nodes, we can model the subsets choice by coloring nodes into two colors, "taken" or "non-taken".

If an element is initially off, we need to take exactly one of the subsets containing it. The corresponding edge should have endpoints with different color. If an element is initially on, we must take none or both subsets : endpoints with same color.

We recognize a sort of bipartition, obviously there are at most two correct colorings for each connected component: fixing the color of a node fix the color of all connected nodes.

Hence, the final answer is the sum for each component, of the size of the smaller side of the partition.

Since the answer exists for i=ni=n, there exists a such partition of the graph (into "red" and "blue" nodes). We can find it with usual dfs, and keep it for lower values of ii.

In order to compute all mimi efficiently, we start from a graph with no edges (i=0i=0), and we add edges with DSU, maintaining in each connected component the count of nodes in red side, and the count of nodes in blue side.

Now, how to deal with elements that appears in exactly one subset? They don't add any edge in the graph, but they force to take one of the sides of the connected component. To simulate this, we can use a special forced flag, or just fix the count of the other side to ++∞ (but be careful about overflow if you do that).

Final complexity : O((n+k)α(k))O((n+k)⋅α(k)).

1290D - Coffee Varieties (hard version)

Easy version (constant 2)

Let's try to maintain representative positions for each value. In the beginning, when we know nothing, every position can be a potential representative.

We will call them alive positions, and using queries, we will try to kill some positions and ending up with exactly one alive position per value. The answer will be the number of alive positions.

Note that when we kill a position, there must be another alive position with the same value. The danger here is to compare a position to a dead position of the same value: we may end up killing the single representative of the value.

Create blocks of size k2k2, (or 11 if k=1k=1). Query 1,2,,n1,2,…,n and kill the element if you get Yes answer. Each value has at least one alive occurrence, its leftmost one. Moreover, all equalities inside blocks are removed.

In order to remove equalities between blocks, compare all unordered pairs of blocks (for each pair, reset the memory, look all elements in the first one, then all elements in the second one, and kill elements in the second one for each Yes answer). Note that we don't need to compare adjacent blocks. The number of queries is a bit less than 2n2k2n2k.

Hard version (constant 1.5)

Querying 1,2,,n1,2,…,n allowed us to compare pairs (i,i+1)(i,i+1) in a very efficient manner because we reuse the memory of the previous comparison. Let's try to generalize this.

Consider a complete graph where nodes are blocks. Comparing pairs of blocks can be seen as covering edges of the graph. We can take any elementary path (that doesn't pass through a node twice), reset the memory and explore blocks in the corresponding order (killing elements for each Yes answer).

Each path will require (number of edges+1)k2(number of edges+1)⋅k2 queries. It's optimal to have disjoint paths (if a path goes through an already visited edge, we can split it there). Hence, we want to use a few disjoint paths to cover all edges.

A randomized DFS works experimentally well (constant around 1.21.2).

However, we can acheive constant 11 using the following zig-zag pattern: ss1s+1s2s+2s→s−1→s+1→s−2→s+2→….

 

 

posted @ 2020-02-03 01:15  kylin_xy  阅读(476)  评论(2编辑  收藏  举报