2020湖南プログラミングコンペティション-C問題解決

質問: 01の文字列を入力してください。位置はどこですか?、1または0になることができます
。01文字列の隣接する位置の絶対値を新しい配列に減算する操作があります。たとえば、1 01は11になることができます。パディングの種類はいくつありますか。このソリューションは、n-1回の操作の後に01文字列値を1にします。
解決策:
隣接する位置の減算の絶対値は、2つの数値のXOR値です。最後に、最終結果へのi番目の数値の寄与はC(n-1、i-1)倍であることがわかります。したがって、C(n-1、i-1)が偶数の場合、この位置の数を考慮する必要はありません。その逆も同様です。kがあると仮定すると、これらの疑問符は、寄与していない位置にある疑問符の数を数えることができます。 1または0の場合、解の数は2 ^ kです。次に、ビットに寄与する疑問符の数を計算し、最後に、これらの疑問符が解の数を計算して、結果1が前の2 ^を乗算するために必要な1の数を計算します。 kが答えです。
コード:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+5,mod=1e9+7;
char s[maxn];
int vis[maxn];
ll fac[maxn];
void cal()
{
    
    
    fac[0]=1;
    for(int i=1; i<maxn; i++)
        fac[i]=fac[i-1]*i%mod;
}
ll qpow(ll a,ll b)
{
    
    
    ll ans=1;
    for(; b; b>>=1,a=a*a%mod)
        if(b&1)
            ans=ans*a%mod;
    return ans;
}

ll C(ll n,ll m)
{
    
    
    if(n<m)
        return 0;
    return fac[n]*qpow(fac[n-m]*fac[m]%mod,mod-2)%mod;
}
int main()
{
    
    
    cal();
    while(cin>>s+1)
    {
    
    
        int n=strlen(s+1);
        int ans=0;
        ll cnt=0;
        ll sum=1;
        for(int i=1;i<=n;i++)
        {
    
    
            int d=(n-1)&(i-1);
            if(d==i-1) vis[i]=1;
            else vis[i]=0;
            if(vis[i]==1)
            {
    
    
                if(s[i]=='1') ans^=1;
                else if(s[i]=='?') cnt++;
            }
            else
            {
    
    
                if(s[i]=='?') sum=sum*2%mod;
            }
        }
        
        ll ca=0;
        if(ans==1)
        {
    
    
            for(int i=0;i<=cnt;i+=2)
            {
    
    
                ca=(ca+C(cnt,i))%mod;
            }
        }
        else
        {
    
    
            for(int i=1;i<=cnt;i+=2)
            {
    
    
                ca=(ca+C(cnt,i))%mod;
            }
        }
        ll res=ca*sum%mod;
        cout<<res<<endl;
    }
}

おすすめ

転載: blog.csdn.net/weixin_45755679/article/details/109188524