• Atcoder Grand Contest 039C(容斥原理,计数DP)


    //每次操作相当于将最低位取反加到最高位(N~1位)
    #define HAVE_STRUCT_TIMESPEC
    #include<bits/stdc++.h>
    using namespace std;
    char s[200007];
    int mi2[200007],num[200007];
    const int mod = 998244353;
    int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int n;
    cin>>n>>s+1;
    mi2[0]=1;
    for(int i=1;i<=n;++i)
    mi2[i]=2ll*mi2[i-1]%mod;
    for(int i=1;i<=n;i+=2)if(n%i==0){//i取偶数会导致经过frequency次操作得到的根本不是它的取反,(奇数段才能经过frequency次操作后首尾相连),任何数经过n次操作都会变成它的取反,相当于每一位都从后向前倒了一遍
    int frequency=n/i;//从大到小枚举次数的一半,即经过frequency次操作使得串变成它的取反,长度长的数可以短的数必定可以,所以在计数时frequency中包含了一些长度短但是经过frequency的因数次操作就满足提议的答案,通过容斥原理在计算长度短的答案时将它们在长度长的答案里减去
    bool flag=1;
    for(int j=1;j<=n&&flag;++j){
    if(s[j]=='1'){//这一位为1,那么必定有长度为n的串,分为frequency段,每一段是相邻段的取反,且前frequency个字符不比s大
    if(j<=frequency||s[j-frequency]=='1'){//特判以frequency个0开头的串是否比s小
    num[frequency]=(num[frequency]+(j<=frequency?mi2[frequency-j]:1))%mod;
    }
    }
    if(j>frequency&&s[j]==s[j-frequency])//特判以frequency个0开头的串是否比s小
    flag=0;
    }
    if(flag)//如果以frequency个0开头的串不比s小,就可以+1,特判只要找不要有相隔frequency个位置的两个字符都是'0'
    num[frequency]=(num[frequency]+1)%mod;
    cout<<num[frequency]<<" ";
    }
    int ans=0;
    for(int i=1;i<=n;++i)if(n%i==0&&(n/i)&1&&num[i]){//从小到大枚举长度
    ans=(ans+2ll*num[i]*i)%mod;//经过i次操作变为原串的取反需要再经过i次操作才变回原串
    for(int j=i*2;j<=n;j+=i)//容斥原理,把已经计算在内的长度较短的数字在长度较长的答案里减去
    num[j]=(num[j]+mod-num[i])%mod;
    }
    cout<<ans;
    return 0;
    }

    保持热爱 不懈努力 不试试看怎么知道会失败呢(划掉) 世上无难事 只要肯放弃(划掉)
  • 相关阅读:
    2015多校.Zero Escape (dp减枝 && 滚动数组)
    UVa-11809
    UVa-1588 Kickdown
    UVa-1587
    UVa-10340
    UVa-202
    UVa-1368
    UVa-232 Crossword Answers
    UVa-227
    UVa-455 Periodic Strings
  • 原文地址:https://www.cnblogs.com/ldudxy/p/11666957.html
Copyright © 2020-2023  润新知