CSP 模拟题 1246
题意:
部分分:
|S|=1 :
送分快速幂
|S|=2 :
给所有可能的两个数字组合(有序)编上号,用 0x 表示x在左边界, x0表示x在右边界,放入一个矩阵内, x,y 向 2^x 的最小位 , 2^y 的最高位转移,所有以4 6为开头的状态向1,6 6,4转移,用矩阵快速幂即可
|S|>2
我们可以发现,给定一个序列,如果我们确定了开头和结尾的一或两位是由哪个数变换成的,我们就可以将整个序列倒推回n-1时的状态。 每个序列最多有四种可能,
仔细看样例会发现当n减少的时候序列的长度减少的速度也很快,且还有可能存在无解的情况,所以通过搜索将|S|化成长度为1或2再计算即可。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #define N 30 8 using namespace std; 9 int n,l; 10 const int p=998244353; 11 char aa[100005]; 12 struct no{ 13 int n,m; 14 long long a[N][N]; 15 }A,B,ans; 16 int dl[N][N],cnt,b[10],a[201][100006],c[100005]; 17 int get_l(int x) 18 { 19 if(!x)return 0; 20 if(x<4) return pow(2,x); 21 return (pow(2,x))/10; 22 } 23 int get_r(int x) 24 { 25 if(!x)return 0; 26 if(x<4)return pow(2,x); 27 return (int)(pow(2,x))%10; 28 } 29 void work(no &A,no B) 30 { 31 ans.n=A.n,ans.m=A.m; 32 for(int i=1;i<=A.n;i++) 33 for(int j=1;j<=A.m;j++) ans.a[i][j]=0; 34 for(int i=1;i<=ans.n;i++) 35 { 36 for(int j=1;j<=cnt;j++) 37 { 38 for(int k=1;k<=cnt;k++) 39 { 40 ans.a[i][j]+=1ll*A.a[i][k]*B.a[k][j]%p; 41 } 42 ans.a[i][j]%=p; 43 } 44 } 45 A=ans; 46 } 47 void ksm(int z,no A,no B) 48 { 49 while(z) 50 { 51 if(z&1) work(A,B); 52 work(B,B); 53 z>>=1; 54 } 55 ans.n=A.n,ans.m=A.m; 56 for(int i=1;i<=ans.n;i++) 57 for(int j=1;j<=ans.m;j++) 58 ans.a[i][j]=A.a[i][j]; 59 } 60 int work2(int L,int dp) 61 { 62 int cnt1=0; 63 a[dp][L+1]=0; 64 for(int i=1;i<=L;i++) 65 { 66 if(a[dp][i]==1||a[dp][i]==6) 67 { 68 if(a[dp][i]==1) 69 { 70 if(a[dp][i+1]!=6) return -1; 71 else 72 { 73 cnt1++; 74 c[cnt1]=4; 75 } 76 } 77 else 78 { 79 if(a[dp][i+1]!=4) return -1; 80 else 81 { 82 cnt1++; 83 c[cnt1]=6; 84 } 85 } 86 i++; 87 } 88 else 89 { 90 cnt1++; 91 if(a[dp][i]==2) c[cnt1]=1; 92 else c[cnt1]=2; 93 } 94 } 95 return cnt1; 96 } 97 void work3(int L); 98 void dfs(int L,int n,int dp); 99 void work3(int L,int n,int dp) 100 { 101 int tmp=work2(L,dp); 102 if(tmp!=-1) 103 { 104 for(int i=1;i<=tmp;i++) a[dp+1][i]=c[i]; 105 dfs(tmp,n,dp+1); 106 } 107 } 108 long long sum; 109 void dfs(int L,int n,int dp) 110 { 111 if(n<0)return; 112 if(L<=2) 113 { 114 ksm(n,A,B); 115 if(L==1) 116 { 117 for(int i=1;i<=5;i++) 118 { 119 sum+=ans.a[1][dl[a[dp][1]][b[i]]]; 120 sum%=p; 121 } 122 } 123 else 124 { 125 int x=a[dp][1],y=a[dp][2]; 126 sum+=ans.a[1][dl[x][y]]; 127 sum%=p; 128 } 129 } 130 else 131 { 132 133 134 if(a[dp][1]==6||a[dp][1]==4) 135 { 136 for(int i=L;i;i--) 137 a[dp][i+1]=a[dp][i]; 138 if(a[dp][1]==6) a[dp][1]=1; 139 else a[dp][1]=6; 140 if(a[dp][L+1]==1||a[dp][L+1]==6) 141 { 142 if(a[dp][L+1]==1) a[dp][L+2]=6; 143 else a[dp][L+2]=4; 144 work3(L+2,n-1,dp); 145 a[dp][L+2]=0; 146 } 147 work3(L+1,n-1,dp); 148 for(int i=1;i<=L;i++) a[dp][i]=a[dp][i+1]; 149 a[dp][L+1]=0; 150 } 151 if(a[dp][L]==1||a[dp][L]==6) 152 { 153 if(a[dp][L]==1) a[dp][L+1]=6; 154 else a[dp][L+1]=4; 155 work3(L+1,n-1,dp); 156 a[dp][L+1]=0; 157 } 158 work3(L,n-1,dp); 159 } 160 } 161 int main() 162 { 163 scanf("%d",&n); 164 scanf("%s",aa+1); 165 l=strlen(aa+1); 166 for(int i=1;i<=l;i++) a[0][i]=aa[i]-'0'; 167 b[1]=1; 168 b[2]=2; 169 b[3]=4; 170 b[4]=6; 171 b[5]=0; 172 for(int i=1;i<=5;i++) 173 { 174 for(int j=1;j<=5;j++) 175 { 176 cnt++; 177 dl[b[i]][b[j]]=cnt; 178 } 179 } 180 for(int i=1;i<=5;i++) 181 { 182 for(int j=1;j<=5;j++) 183 { 184 int x,y; 185 x=b[i],y=b[j]; 186 B.a[dl[x][y]][dl[get_r(x)][get_l(y)]]++; 187 if(x==4||x==6) 188 B.a[dl[x][y]][dl[get_l(x)][get_r(x)]]++; 189 } 190 } 191 B.n=B.m=cnt; 192 A.n=1,A.m=cnt; 193 A.a[1][dl[0][1]]=A.a[1][dl[1][0]]=1; 194 dfs(l,n,0); 195 printf("%lld\n",sum); 196 return 0; 197 }