zoukankan      html  css  js  c++  java
  • codeforces1045B Space Isaac 【manacher】【差分】

    题目大意:

    题目是将$[0,m)$的数划成了两个集合,其中一个集合的元素个数不超过$n$。问在第一个集合中选出的数加上第二个集合中选出的数的和中没有出现的数有哪些。

    题目分析:

    很有意思的一道题。方便起见,接下来的所有表述在模意义下进行。选出的数集合用$a_1 sim a_n$表示

    考虑给出的集合,$k$无法由两个集合中任选一个数的和表示等价于对于给出的集合元素$a_i$,$k-a_i$也在给出的集合之中。

    这样来看答案不会超过$n$。也就是你对选出的集合中最小的数考虑,它与另一个选出的数配对。且每个选出的数都能这样配对。

    假设你现在让$a_1$与$a_i$配对,那么$a_2 sim a_{i-1}$必然首尾配对。且$a_{i+1}$一定与$a_n$配对,否则$a_n$找不到配对对象。

    这样我们将问题化为了两个环。内部要与最外层答案一致意味着从左到右增加了$k$,那么从右到左也要减少$k$,换句话说它的差分数组是回文的。

    所以manacher判回文就行了。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 200200;
     5 
     6 int n,m;
     7 int a[maxn],x[maxn],ans[maxn],num;
     8 
     9 int ss[maxn*2],f[maxn*2],ct,rr;
    10 
    11 void read(){
    12     scanf("%d%d",&n,&m);
    13     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    14 }
    15 
    16 void manacher(){
    17     for(int i=1;i<=n;i++) ss[i*2] = x[i];
    18     for(int i=1;i<=n;i++) ss[i*2-1] = -1; // to replace '$'
    19     ss[2*n+1] = -1; f[1] = 1,rr = 1,ct = 1;
    20     for(int i=2;i<=2*n+1;i++){
    21         if(rr < i) f[i] = 1; else f[i] = min(rr-i+1,f[2*ct-i]); 
    22         while(i+f[i]<=2*n+1&&i-f[i]>=1&&ss[i+f[i]]==ss[i-f[i]])f[i]++;
    23         if(i+f[i]-1 > rr) ct = i,rr = i+f[i]-1;
    24     }
    25 }
    26 
    27 int chk(int l,int r){
    28     if(l >= r) return 1;
    29     int cent = l+r;
    30     int ll = cent-f[cent]+1,rr = cent+f[cent]-1;
    31     if(ll <= 2*l && rr >= 2*r) return 1;
    32     else return 0; 
    33 }
    34 
    35 void work(){
    36     for(int i=1;i<=n;i++) x[i] = a[i] - a[i-1];
    37     if(n == 1){printf("1
    %d",(a[1]+a[1])%m);return;}
    38     manacher();
    39     for(int i=1;i<n;i++){
    40         if((a[1] + a[i])%m == (a[i+1] + a[n])%m){
    41             if(chk(2,i)&&chk(i+2,n)){
    42                 ans[++num] = (a[1]+a[i])%m;
    43             }
    44         }else continue;
    45     }
    46     if(chk(2,n)){ans[++num] = (a[1]+a[n])%m;}
    47     sort(ans+1,ans+num+1);
    48     printf("%d
    ",num);
    49     for(int i=1;i<=num;i++){
    50         printf("%d ",ans[i]);
    51     }
    52 }
    53 
    54 int main(){
    55     read();
    56     work();
    57     return 0;
    58 }
  • 相关阅读:
    Xcode 单元测试
    Oracle积累
    懒人小技巧, Toad 常用偷懒方法
    改变UITableView选中行高亮的颜色
    苹果企业版帐号申请记录
    RGB颜色设置错误
    IOS 设置文件是否使用ARC
    懒人的小技巧, 批处理修改IP
    Go连接MYSQL
    Go中的函数和闭包
  • 原文地址:https://www.cnblogs.com/Menhera/p/9800156.html
Copyright © 2011-2022 走看看