大水題(water)
阿新 • • 發佈:2017-08-17
open int [1] eve i++ mes gre cto 一個 提示
如果兩個生成矩陣在其中一個旋轉 $\color{green}{180}$ 度後可以重疊,則稱這兩個矩陣是相同的。 $$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位嚴格小於,自然滿足條件,如果只是等於,就要翻轉之後也是小於等於的。
題目描述
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位的。那麽答案為:
我們在枚舉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)