八校联考第一场第二试 大水题

【题意】

  dzy 定义一个n^2 位的数的生成矩阵A 为一个大小为n*n 且Aij 为这个数的第i*n+j-n位的矩阵。

  现在dzy 有一个数n^2 位的数k,他想知道所有小于等于k 的数的n*n 生成矩阵有多少种。(如果不足n^2 位则补前缀零)
  如果两个生成矩阵在其中一个旋转180 度后可以重叠,则称这两个矩阵是相同的。
  n为小于等于1000的正偶整数。
【题解】
  以前的模拟题今天被虐了。。。。好久没写博了更一下吧。。
  实际上直接可以当作一个n*n位的整数处理。
  设F(I)为i翻转后的数。
    答案可以分为3部分求:
    一是小于等于k的数的个数(设为S1)。
    二是小于等于k且翻转后的数也小于等于k的数个数(设为S2)。
    三是小于等于k且等于自身翻转的数的个数(设为S3)。
    于是$Ans=k-\frac{\sum_{i=1}^{k}[f[i]\in (1,k)]-\sum_{i=1}^{k}[f[i]==i]}{2}=S1-(S2-S3)/2$
    这三部分可以用数位dp求出:
    设x为
    dp[i][j][p]表示枚举的整数在
    1.当前处理到第i位(这一维可以滚动的);
    2.j为一个01变量,标记创造的整数前一段长度为i的部分是小于还是等于k的前一部分;
    3.p也是一个01变量,表示这一段数翻转后小于等于还是大于原数的后一部分;
    状态下的合法个数。
    状态转移方程比较麻烦,细节比较多吧,注意一下各个状态之间的关系就行了,所以具体不多说了(好吧我比较懒。。)
    于是  S1=k
        S2=dp[n][0][0]+dp[n][1][0]
        S3=dp[n/2][0][0]+dp[n/2][0][1]+dp[n/2][1][0]
    最后代入原式即可求得答案。
【代码】
 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #define ll long long
 5 #define mo 1000000007
 6 using namespace std;
 7 char str[1001000];
 8 int n,s1,s2,s3,s,dp[1000100][2][2],a[1000100];
 9 int main()
10 {
11     cin>>n;
12     scanf("%s",str+1);
13     n=n*n;
14     for (int i=1;i<=n;++i)
15         a[i]=str[i]-48;
16     dp[0][1][0]=1;
17     for (int i=0;i<n;++i)
18         for (int j=0;j<2;++j)
19             for (int k=0;k<2;++k)
20             {
21                 if (j==0)    s1=10; else s1=a[i+1];
22                 if (k==0)    s2=a[n-i]+1; else s2=a[n-i];
23                 dp[i+1][0][0]=(dp[i+1][0][0]+(ll)dp[i][j][k]*min(s1,s2)%mo)%mo;
24                 if (j==1 && s2>a[i+1])    dp[i+1][1][0]=(dp[i][j][k]+dp[i+1][1][0])%mo;
25                 dp[i+1][0][1]=(dp[i+1][0][1]+(ll)dp[i][j][k]*max(0,s1-s2)%mo)%mo;
26                 if (j==1 && s2<=a[i+1])    dp[i+1][1][1]=(dp[i+1][1][1]+dp[i][j][k])%mo;
27             }    
28     s1=((dp[n][0][0]+dp[n][0][1])%mo+(dp[n][1][0]+dp[n][1][1])%mo)%mo;
29     s2=(dp[n][0][0]+dp[n][1][0])%mo;
30     s3=((dp[n/2][0][0]+dp[n/2][1][0])%mo+dp[n/2][0][1])%mo;    
31     s=s1-(ll)(s2-s3)*((mo+1)/2)%mo-1;
32     cout<<(s%mo+mo)%mo<<endl;
33     return 0;
34 }
View Code
原文地址:https://www.cnblogs.com/Bleacher/p/7147732.html