码迷,mamicode.com
首页 > 其他好文 > 详细

大水题(water)

时间:2017-08-17 21:37:19      阅读:187      评论:0      收藏:0      [点我收藏+]

标签:class   using   cst   输入输出   加速   cli   stdout   ret   names   

题目描述
dzy 定义一个 $n^2$ 位的数的生成矩阵 $A$ 为一个大小为 $n \times n$ 且 Aij 为这个数的第 $i \times n+j-n$ 位的矩阵。
现在 dzy 有一个数 $n^2$ 位的数 k,他想知道所有小于等于 k 的数的 $n \times n$ 生成矩阵有多少种。(如果不足 $n^2$ 位则补前缀零)
输入输出格式
输入格式
第一行一个数 $n$,第二行一个 $n^2$ 位的数 $k$
输出格式
仅一行表示答案,答案可能很大,你只需输出答案对 $10^9 + 7$ 取模后的结果。
样例 1

输入1
2
1000
输出1
954
数据范围
对于 $30\%$ 的数据 $n \le 2$
对于 $100\%$ 的数据 $n \le 1000$,且 $n$ 为偶数
提示
如果两个生成矩阵在其中一个旋转 $\color{green}{180}$ 度后可以重叠,则称这两个矩阵是相同的。

题解:

这道题看了就一脸懵逼,大火题被说成了大水题了.........
言归正传:
先和网上一样贴公式:
设$f(i)$为$i$在$n^2$位中翻转后的数。
$$ans=k- \frac{\sum_{i}^{f(i) \in [1,k]}1 - \sum_{i}^{f(i) \in [1,k]}(f(i)==i)}{2}$$就是翻转之后的数的个数减去回文数,再除以2就是重复统计的数了。
设$$f[i][j][k],i \in [1,k],j \in [0,1],k \in [0,1]$$为当前枚举到第i位,前i位是否是严格的小于k的前i位的(是为1否为0),将前i位翻转之后的数是否是严格小于等于k的后i位的。那么答案为:
$$ans=k- \frac{(f[n][1][1]+f[n][0][1])-(f[n/2][1][0]+f[n/2][1][1]+f[n/2][0][1])}{2}$$
我们在枚举i,j,k和数字1~9时,就保证前i为严格小于等于,那么j=1就是严格小于,否则就是等于了。
$$(f[n][1][1]+f[n][0][1])$$是$$\sum_{i}^{f(i) \in [1,k]}1$$。前n位不管是小于还是等于,只要翻转之后也在1~n之间就行了。
$$(f[n/2][1][0]+f[n/2][1][1]+f[n/2][0][1])$$是$$\sum_{i}^{f(i) \in [1,k]}(f(i)==i)$$前n/2位翻转之后把后n/2位给补齐了,正好是一个回文数,那么前n/2位严格小于,自然满足条件,如果只是等于,就要翻转之后也是小于等于的。

技术分享
 1 #include<queue>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define RG register
 8 using namespace std;
 9 const int mod=1000000007;
10 long long int n,ans,GG,Two=500000004,X,Y,Z;
11 char s[1000099];
12 int a[1000099],dp[1000099][2][2];
13 int main()
14 {
15   freopen("water.in","r",stdin);
16   freopen("water.out","w",stdout);
17   cin>>n;
18   n*=n;
19   scanf("%s",s+1);
20   for(int i=1;i<=n;i++)
21     {
22       a[i]=s[i]-0;
23       GG=GG*10+a[i];
24       GG%=mod;
25     }
26   dp[0][0][1]=1;
27   for(RG int i=0;i<n;i++)
28     for(RG int j=0;j<=1;j++)
29       for(RG int k=0;k<=1;k++)
30     if(dp[i][j][k]!=0)//加速(没卵用)
31       for(RG int l=0;l<=9;l++)//枚举i+1位的数字。
32         {
33           if(l<=a[i+1]||j)//这一位要小于等于或者之前已经小于了。
34         {
35           RG bool b=(l<a[i+1])||j;//这里不能取等号,因为j代表的是严格小于才为1。
36           RG bool c=(l==a[n-i]&&k)||(l<a[n-i]);//。。。严格的小于等于,因为n-i是从后往前的如果后面的相等,这以为自然可以相等,否则这以为必须严格小于才行。
37           dp[i+1][b][c]+=dp[i][j][k];
38           dp[i+1][b][c]%=mod;
39         }
40           else break;
41         }
42   X=(dp[n][0][1]+dp[n][1][1])%mod; 
43   Y=(dp[n/2][1][0]+dp[n/2][0][1]+dp[n/2][1][1])%mod;
44   Z=((X-Y)*Two)%mod;
45   ans=(GG-Z+mod)%mod;
46   cout<<ans<<endl;
47   return 0;
48 }
View Code

 

大水题(water)

标签:class   using   cst   输入输出   加速   cli   stdout   ret   names   

原文地址:http://www.cnblogs.com/D-O-Time/p/7384191.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!