1. 程式人生 > >2018牛客多校第四場 A Ternary String

2018牛客多校第四場 A Ternary String

設dp[i]為刪掉原本的第i位需要經過多少天,然後可以根據規則發現一些規律,如果第i位是2的話,dp[i]=6*2^dp[i-1]-3,如果是第1位的話就是dp[i]=2^dp[i-1]+2,0:dp[i]=dp[i-1]+1,然而dp陣列是非常大的,需要對mod進行取模,但是呼叫之前的dp[i-1]已經是取模過得,那麼dp[i-1]的冪次必須是要對phi(mod)取模,而dp[i-1]又是由dp[i-2]轉移過來的,那麼在計算dp[i-1]的時候2^dp[i-2]這一項,dp[i-2]要對phi(phi(mod))取模,預處理出對於每個mod的phi[mod],就可以nlogn的遞迴呼叫了。然而考場上並沒有想到,而是直接對每一個phi[p]都遞推一遍,n*30*log(1e9),無盡的TLE,最後向aols求取了一波人生的經驗,先預處理出一個數組mi[j][i],代表2^i對phi[j]取模的結果,在遞推的時候如果2的冪小於maxi,那麼直接從數組裡取得,不進行快速冪。於是我發現maxi必須開1e6,再大1e5超空間,再小2*1e5超時,最後3579ms卡過去的。。。不過如果能想到遞迴呼叫,就140+ms能過了。

#include<bits/stdc++.h>
#define X first
#define Y second
#define pb push_back
#define mk make_pair
#define rep(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
typedef long long LL;
const int maxn=1e6,mod=1e9+7,M=30,maxl=1e5+5;
int n,m;
int f[maxl][M];
int mi[M][maxn];
char s[maxn];
int a[M];
inline int Pow(int a,int b,int mod)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=((LL)ans*a)%mod;
        a=((LL)a*a)%mod;
        b>>=1;
    }
    return ans;
}
  
inline int calc(int t,int tt,int j)
{
    int mod=a[j];
    if(mod==1)return 0;
    if(t==1ll)return 2ll;
    if(tt<maxn)
        return (3ll*(1ll*mi[j][tt]-1ll+mod)%mod-t+mod)%mod;
    else
    return (3ll*(1ll*Pow(2ll,tt,mod)-1ll+mod)%mod-t+mod)%mod;
}
  
int main()
{
    a[1]=1;
    a[2]=2;
    a[3]=4;
    a[4]=8;
    a[5]=16;
    a[6]=32;
    a[7]=64;
    a[8]=128;
    a[9]=256;
    a[10]=512;
    a[11]=1024;
    a[12]=2048;
    a[13]=4096;
    a[14]=8192;
    a[15]=16384;
    a[16]=32768;
    a[17]=65536;
    a[18]=131072;
    a[19]=262144;
    a[20]=524288;
    a[21]=1048576;
    a[22]=2097152;
    a[23]=5242880;
    a[24]=19660800;
    a[25]=79872000;
    a[26]=243900800;
    a[27]=500000002;
    a[28]=1000000006;
    a[29]=1000000007;
    for(int i=2;i<M;i++)
    {
        mi[i][0]=1;
        for(int j=1;j<maxn;j++)
            mi[i][j]=(mi[i][j-1]<<1)%a[i];
    }
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        //memset(f,0,sizeof(f));
        for(register int i=2;i<M;++i)
            f[1][i]=(s[1]-'0'+1)%a[i];
        for(register int i=2;i<=n;++i)
        {
            if(s[i]=='0')
                for(register int j=2;j<M;++j)
                    f[i][j]=(f[i-1][j]+1)%a[j];
            else if(s[i]=='1')
                for(register int j=2;j<M;++j)
                    f[i][j]=((f[i-1][j]<<1)+2)%a[j];
            else
                for(register int j=2;j<M;++j)
                    f[i][j]=(f[i-1][j]+calc(f[i-1][j]+1,f[i-1][j-1]+1,j)+1)%a[j];
        }
        printf("%d\n",f[n][29]);
    }
    return 0;
}
/*
3
012
22
  
*/
#include<bits/stdc++.h>
#define X first
#define Y second
#define pb push_back
#define mk make_pair
#define rep(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
typedef long long LL;
const int maxn=1e5+5,mod=1e9+7,M=30;
int n,m;
char s[maxn];
int a[M];
inline int Pow(LL a,LL b,int mod)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=((LL)ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return (int)ans;
}
 
inline LL calc(int t,int mod)
{
    if(t==0)return 0;
    if(mod==1)return 0;
    if(s[t]=='0')return (calc(t-1,mod)+1)%a[mod];
    else if(s[t]=='1')return (calc(t-1,mod)*2+2)%a[mod];
    else return (3ll*(Pow(2ll,calc(t-1,mod-1)+1,a[mod])-1ll)%a[mod]+a[mod])%a[mod];
}
 
int main()
{
    a[1]=1;
    a[2]=2;
    a[3]=4;
    a[4]=8;
    a[5]=16;
    a[6]=32;
    a[7]=64;
    a[8]=128;
    a[9]=256;
    a[10]=512;
    a[11]=1024;
    a[12]=2048;
    a[13]=4096;
    a[14]=8192;
    a[15]=16384;
    a[16]=32768;
    a[17]=65536;
    a[18]=131072;
    a[19]=262144;
    a[20]=524288;
    a[21]=1048576;
    a[22]=2097152;
    a[23]=5242880;
    a[24]=19660800;
    a[25]=79872000;
    a[26]=243900800;
    a[27]=500000002;
    a[28]=1000000006;
    a[29]=1000000007;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        printf("%lld\n",calc(n,29));
    }
    return 0;
}
/*
3
012
22
000
 
*/