[CF1045B]Space Isaac

题目:Space Isaac

传送门:http://codeforces.com/contest/1045/problem/B

分析:

1)我们考虑不能被表示出来的数。

2)设这个数为P,对所有的数x,如果$x \in A$,在那么$(p-x)mod m \in A $;如果$x \in B$,在那么$(p-x)mod m \in B $。否则显然可以表示出这个数。

3)$x$可以分为两段: 小于$P$和大于$P$的情况。当$x<P$时 $P-x<P$;$x>P$时$P-x>P$。

4)考虑枚举分段点$i$,$P=(a[1]+a[i])%m=(a[2]+a[i-1])%m=...$,这就类似个回文串啊。比$P$大的部分同理。

5)然后就是这段经典操作,$b[i]=a[i+1]-a[i];$,再求回文串了。

方法一:

6)回文串可以哈希,顺着、反着各一遍求区间hash值,然后比较是否相等,

7)哈希基于概率,有可能会冲突,简单的做法是双哈希,就是这么暴力,如果还不能解决,那就再来一遍。

 

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL; 
const int maxN=200005;
const ULL HA=41793404541;
int n,m;
int a[maxN],b[maxN];
ULL fac[maxN],pre[maxN],nxt[maxN];
int ansn,ans[maxN];
bool check(int l,int r){
    return pre[r]-pre[l-1]*fac[r-l+1]==nxt[l]-nxt[r+1]*fac[r-l+1];
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    for(int i=1;i< n;++i)b[i]=a[i+1]-a[i];
    fac[0]=1;
    for(int i=1;i<=n;++i)fac[i]=fac[i-1]*HA;
    for(int i=1;i<=n;++i)pre[i]=pre[i-1]*HA+(ULL)b[i];
    for(int i=n-1;i ;--i)nxt[i]=nxt[i+1]*HA+(ULL)b[i];
    for(int i=1;i<=n;++i){
        bool pd=true;
        if(i!=1)pd&=check(1,i-1);
        if(i!=n){
            pd&=(a[1]+a[i]==a[i+1]+a[n]-m);
            if(i!=n-1)pd&=check(i+1,n-1);
        }
        if(pd)ans[++ansn]=(a[1]+a[i])%m;
    }
    printf("%d\n",ansn);
    sort(ans+1,ans+ansn+1);
    for(int i=1;i<=ansn;++i)printf("%d ",ans[i]);
    return 0;
}

 

方法二

8)manachar也是用来解决回文串的有力武器,这里先埋一个坑,捂脸逃。。

题外:

这种题现场过的都是神仙(大雾

 

posted @ 2019-02-17 21:34  hjj1871984569  阅读(248)  评论(0编辑  收藏  举报