PKUSC2018 神仙的游戏

4 篇文章 0 订阅

题意

数据范围

Analysis

首先分析一下 border b o r d e r 的性质,可以知道,一个长为 len l e n border b o r d e r 代表: leni=0Si=Snlen+i ∑ i = 0 l e n S i = S n − l e n + i ,那么观察式子,可以发现,事实上一个长为 len l e n border b o r d e r 成立的必要条件,是所有位置对于% (nlen) ( n − l e n ) 分组,在同一组中的字符相等。那么考虑一对 0,1 0 , 1 它们出现的位置为 x,y x , y ,那么所有满足长为 abs(xy)|(nlen) a b s ( x − y ) | ( n − l e n ) border b o r d e r 都不满足条件。考虑用生成函数来解决问题,设 A(x)=n1i=0[Si==0]xi A ( x ) = ∑ i = 0 n − 1 [ S i == 0 ] x i B(x)=n1i=0[Sni==0] B ( x ) = ∑ i = 0 n − 1 [ S n − i == 0 ] ,那么将这两个多项式乘起来,我们就可以根据每一项系数,来去除不合法的 border b o r d e r ,进而得到答案。

Code

# include<cstdio>
# include<algorithm>
# include<cstring>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
const ll mo = 998244353;
const int g = 3;
const int invg = (mo + 1) / 3;
char s[N];
int a[N << 2],b[N << 2],rev[N << 2];
int n,m,l;
inline int pow(int x,int p)
{
    int ret = 1;
    for (; p ; p >>= 1,x = (ll)x * x % mo)
        if (p & 1) ret = (ll)ret * x % mo;
    return ret;
}
inline void DFT(int *f,int len,int opt)
{
    for (int i = 0 ; i < len ; ++i) if (i < rev[i]) swap(f[i],f[rev[i]]);
    for (int i = 1 ; i < len ; i <<= 1)
    {
        int wn = pow(~opt ? g : invg,(mo - 1) / (i << 1));
        for (int j = 0 ; j < len ; j += (i << 1))
        {
            int w = 1;
            for (int k = 0 ; k < i ; ++k,w = (ll)w * wn % mo)
            {
                int x = f[j + k],y = (ll)w * f[i + j + k] % mo;
                f[j + k] = (x + y) % mo,f[i + j + k] = (x - y + mo) % mo;
            }
        }
    }
    if (opt == -1)
    {
        int x = pow(len,mo - 2);
        for (int i = 0 ; i < len ; ++i) f[i] = (ll)f[i] * x % mo;
    }
}
int main()
{
    scanf("%s",s); n = strlen(s);
    for (int i = 0 ; i < n ; ++i)
    {
        a[i] = (s[i] == '0') ? 1 : 0;
        b[i] = (s[n - i - 1] == '1') ? 1 : 0;
    }
    for (m = 1 ; m < (n << 1) ; m <<= 1,++l);
    for (int i = 0 ; i < m ; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
    DFT(a,m,1); DFT(b,m,1);
    for (int i = 0 ; i < m ; ++i) a[i] = (ll)a[i] * b[i] % mo;
    DFT(a,m,-1); ll ans = 0;
    for (int i = 1 ; i < n ; ++i)
    {
        bool flag = 1;
        for (int j = i ; j < n ; j += i) if (a[n - 1 - j] | a[n - 1 + j]) { flag = 0; break; }
        if (flag) ans ^= (ll)(n - i) * (n - i);
    }
    printf("%lld\n",ans ^ ((ll)n * n));
    return 0;
} 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值