Time Limits: 1000 ms Memory Limits: 524288 KB Detailed Limits
Description
dzy 定义一个n^2 位的数的生成矩阵A 为一个大小为n*n 且Aij 为这个数的第i*n+j-n位的矩阵。
现在dzy 有一个数n^2 位的数k,他想知道所有小于等于k 的数的n*n 生成矩阵有多少种。(如果不足n^2 位则补前缀零)
Input
第一行一个数n,第二行一个n^2 位的数k
Output
仅一行表示答案,答案可能很大,你只需输出答案对10^9 + 7 取模后的结果。
Sample Input
2 1000
Sample Output
954
Data Constraint
对于30% 的数据n<=2
对于100% 的数据n <=1000,且n为偶数
Hint
【提示】
如果两个生成矩阵在其中一个旋转180 度后可以重叠,则称这两个矩阵是相同的。
总结:
比赛的时候只打了暴力,像这种数位dp, 从来没见过。有时候能增加状态数解决dp。
题解:
数位dp。
对于后面的分子, 我们可以dp求出。
f[i][j][k]表示构造到第i位, j = 0 / 1, k = 0 / 1
j 等于1表示 构造的数组前i位和a数组相等, k等于1 表示前i位翻转后 <= a最后的i位
转移 :
f[i][j][k] - > f[i + 1][a][b]
a b 是未知的, 我们尝试枚举i + 1上我们构造的数字, 设为l。
转移的条件 1:第i位前就小于a[], 或者前面等于, 这一位小于等于。
a 为 1的条件 前面就小于, 或这一位小于。
b为1的条件 (注意, 前i位要翻转了, 故越后面的数位比较优先级越高) : 之前相等吗现在<= 或 当前数 < a[n - i]
转移时注意 :
- 构造的数组时刻小于等于a, 若大于了, 对答案毫无影响, 算他干嘛。
- f[i][j][k] - > f[i +1][a][b]的过程中, 若f[i][j][k] = 0, 对答案也毫无影响。
答案:
我们分别算出s1, s2.
s1
要求双重 <=k
当构造的数组等于a时, f[n][0][1]
当<时, f[1][1]
s2
f[n/2]
当为0时, 前面等于后面只能<=
当为1时, 后面随意。
初始化f[0][0][1] = 1
#include<bits/stdc++.h>
#define open(x) freopen(x".in", "r", stdin);freopen(x".out", "w", stdout)
#define mem(a, b) memset(a, b, sizeof(a))
#define mcy(a, b) memcpy(a, b, sizeof(a))
#define pf printf
#define sf scanf
#define fo(i, a, b) for( ll i = a; i <= b; ++i)
#define fown(i, a, b) for( ll i = a; i >= b; --i)
#define em(p, x) for(ll p=tail[x];p;p=e[p].fr)
#define ll long long
#define N 1010
#define maxn N * N
#define mod (ll)(1e9 + 7)
using namespace std;
template<class T>
T in(T &x) {
x=0;
char ch = getchar();
ll f = 0;
while(ch < '0' || ch > '9') f |= ch == '-', ch = getchar();
while(ch >= '0' && ch <= '9') x = (x<<1) + (x<<3) + ch - '0', ch = getchar();
x = f ? -x : x;
return x;
}
ll n, k, ans;
ll f[maxn][2][2], a[maxn];
ll sqr(ll x) {return x * x% mod;}
ll power(ll x, ll k) {
if(k == 0 ) return 1;
if(k & 1) return x * sqr(power(x, k / 2)) % mod;
return sqr(power(x, k / 2));
}
int main() {
open("water");
sf("%lld\n", &n);
n = n * n;
char ch;
fo(i, 1, n) {
sf("%c", &ch);
ans = (ans * 10 % mod + ch - '0') % mod;
a[i] = ch - '0';
}
sf("\n");
f[0][0][1] = 1;
fo(i, 0, n - 1)
fo(j, 0, 1)
fo(k, 0, 1) if(f[i][j][k])
fo(l, 0, 9)
if(j || a[i + 1] >= l) {
ll b, c;
b = j || (l < a[i + 1]);
c = (k && a[n - i] == l) || (a[n - i] > l);
(f[i + 1][b][c] += f[i][j][k]) %= mod;
}
ll s1 = 0, s2 = 0;
(s1 = f[n][0][1] + f[n][1][1])%=mod;
(s2 = (f[n/2][1][0] + f[n/2][1][1])% mod+ f[n/2][0][1])%=mod;
ans = ans - ((s1 - s2) % mod + mod) % mod * power(2, mod - 2) % mod;
(ans += mod) %= mod;
pf("%lld\n", ans);
return 0;
}
O(n^2)