QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#553888 | #4169. 代码拍卖会 | David_Mercury | 0 | 0ms | 0kb | C++14 | 3.6kb | 2024-09-08 22:10:33 | 2024-09-08 22:10:39 |
answer
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 505, MAXLOG = 25;
const ll Mod = 999911659;
int n, p, w = 20;
ll f[MAXLOG][MAXN][2], g[MAXN], h[MAXN][MAXLOG][MAXN], Bit[MAXN];
inline ll Quick_Power(ll x, ll p, ll Mod){
if(!p) return 1;
ll tmp = Quick_Power(x, p>>1, Mod);
if(p&1) return tmp*tmp%Mod*x%Mod;
else return tmp*tmp%Mod;
}
int main(){
cin>>n>>p;
ll x = n;
for(int i = 1; i <= w; i++, x /= 10) Bit[i] = x%10;
g[0] = 1;
for(int i = 1; i <= p; i++) g[i] = g[i-1]*10%p;
f[0][1][1] = f[0][1][0] = 1;
for(int i = 1; i <= w; i++)
for(int j = 0; j < p; j++)
for(int k = 0; k < 10; k++){
if(k < Bit[i]) (f[i][j*g[k]%p][1] += f[i-1][j][0]) %= Mod;
if(k == Bit[i]) (f[i][j*g[k]%p][1] += f[i-1][j][1]) %= Mod;
(f[i][j*g[k]%p][0] += f[i-1][j][0]) %= Mod;
}
// for(int i = 0; i < p; i++) cout<<f[w][i][1]<<" "; puts("");
h[0][0][0] = 1;
for(int i = 1; i <= 8; i++) h[0][i][0] = h[0][i-1][0]*f[w][0][1]%Mod;
for(int i = 1; i < p; i++)
for(int j = 0; j <= 8; j++)
for(int k = 0; k < p; k++){
ll ans = 1;
for(int t = 0; t <= j; t++){
(h[i][j][k] += h[i-1][j-t][(k-i*t%p+p)%p]*ans) %= Mod;
ans = ans*(f[w][i][1]+t)%Mod*Quick_Power(t+1, Mod-2, Mod)%Mod;
}
}
// for(int i = 0; i < p; i++)
// for(int j = 0; j <= 8; j++)
// for(int k = 0; k < p; k++) cout<<i<<" "<<j<<" "<<k<<" "<<h[i][j][k]<<endl;
int tmp = (p-Quick_Power(10, n, p)+9)%p;
// cout<<tmp<<endl;
cout<<h[p-1][8][tmp];
return 0;
}
/*
我猜还是矩阵乘法(不对,n^3 就已经爆 1e8 了)
f[j][i][k]:数码为 i,第 j 位,模 p 余 k
f[j+1][t][(k+t)%p] += f[j][i][k], t >= i
如果 p <= 10 的话这倒是可以矩阵乘法计算(为了避免爆栈,不要写递归ksm)
而当 p > 10 的话这实际可以线性递推出来,因为每个状态唯一对应一个前驱……
并不正确。因为 k 虽然一样,可能存在多个 i
或许注意力偏了,这本质是一道数论题
111...11 = (10^len-1)/9
经过推导,有:9*10^n - 1 = \sum_{i=1}^8 10^{x_i}, 0 <= x_i <= n 且 x_i 单调递增
然后可以设法算出 f[x] 表示 10^y mod p = x 的个数
怎么算?其实可以数位 DP
那么如何求出最终的 x_i 可重集?
如果没有 x_i 是集合的限制,其实很简单。
钦定一个数 v_i 为最小值,然后将它提出来,继续处理剩下的数——但这么做,上界无法保证。
或许可以尝试容斥?不可以。
式子推错了(
\sum_{i=1}^8 10^{x_i} = -10^n+9,0 <= x_i <= n 且 x_i 单调递增
如果没有 x_i 是多重集的限制,其实有一个简单 DP:
h[i][j] 表示前 i 个数码,余数为 j,然后通过枚举这一位填的余数 k 转移
这里有一个奇妙 Trick:如果我们最开始就枚举转移 k,就可以等同于枚举集合(类似多重背包)
但同一 k 的方案之间仍可能存在重复,需要处理如下问题:
现有 a 种物品,你要从中选出 b 个,每种物品数量不限,求方案数
多重集的组合数(无限)
可以等价为 (1+x+x^2+...+x^b)^a[x^b]
其实已经可以用生成函数了,但能不能再简单一点?
= (1-x)^(-a)[x^b]
再用二项式定理展开:
\sum_{i=0}^inf (-1)^i a^{i上升幂}/i! (-x)^i = \sum_{i=0}^inf a^{i上升幂}/i! x^i
那么答案就是 a^{b 次上升幂}/b!
怎么过不了样例???
哦!
如果 9 在模 p 意义下为 0 最开始的结论就不成立
但显然这仅当 p=3/9 时有可能
而能被 3/9 整除的数有数字和也能被二者整除的特性
有个简单的矩阵快速幂做法:f[i][j][k]:前 j 个数码,数码和模 p
*/
详细
Pretests
Final Tests
Test #1:
score: 0
Time Limit Exceeded
input:
982 473
output:
result:
Test #2:
score: 0
Runtime Error
input:
82749201374821543 5
output:
result:
Test #3:
score: 0
Runtime Error
input:
17327482917364121 7
output:
result:
Test #4:
score: 0
Runtime Error
input:
28489124728192763 1
output:
result:
Test #5:
score: 0
Runtime Error
input:
40285729174762941 25
output:
result:
Test #6:
score: 0
Time Limit Exceeded
input:
999999 499
output:
result:
Test #7:
score: 0
Runtime Error
input:
58390378572931426 113
output:
result:
Test #8:
score: 0
Runtime Error
input:
38475729495732951 491
output:
result:
Test #9:
score: 0
Runtime Error
input:
71937591037847128 487
output:
result:
Test #10:
score: 0
Runtime Error
input:
100000000000000000 491