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
#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
#include
#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
 
*/

 

你可能感兴趣的:(欧拉函数,递推)