Topcoder10566 IncreasingNumber

IncreasingNumber

一个数是Increasing当且仅当它的十进制表示是不降的,\(1123579\)

\(n\) 位不降十进制数中被 \(d\) 整除的有多少个。

\(n\leq 10^{18},d \leq 500\)

题解

简单的想法:\(dp(i,j,k)\) 表示前 \(i\) 位已填好,第 \(i\) 位是 \(j\),模 \(d=k\) 的数的个数。

但是即使加上矩阵优化,复杂度仍然达到了 \(O(10^3d^3 \log n)\)。不可过。

观察性质:一个数是Increasing的当且仅当它是至多 \(9\) 个全 \(1\) 的数的和。

由于最终产生的数必须严格 \(n\) 位,不能有前导 \(0\),所以我们对位数 \(< n\) 的全 \(1\) 数和 \(=n\) 的全 \(1\) 数分开做。

我们可以用 \(dp(k,j,mod)\) 表示考虑了 \(\bmod d=0\sim k\) 的全 \(1\) 数,用了 \(j\) 个数,余数是 \(mod\) 的方案数。

转移系数是 \(\binom{j+cnt_k-1}{cnt_k-1}\),其中 \(cnt_k\) 表示 \(1\sim n-1\) 位的全 \(1\) 数中,\(\bmod d=k\) 的数的个数。开始我想的是 \(cnt_k^j​\),后来发现这样就相当于有标号了。

考虑 \(n\) 位全 \(1\) 数模 \(d\) 的余数和 \(cnt\) 数组如何求。可以利用 \(d\) 比较小来找循环节。注意循环节和起始点可能类似符号 \(\rho\) ,要加上对 \(n\) 的特判。

AC程序:

#include
using namespace std;
template T read(){
    T x=0,w=1;char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*w;
}
template T read(T&x){
    return x=read();
}
#define CO const
#define IN inline
typedef long long LL;

CO int mod=1000000000+7;
IN int add(int a,int b){
    return (a+=b)>=mod?a-mod:a;
}
IN int mul(int a,int b){
    return (LL)a*b%mod;
}
IN int fpow(int a,int b){
    int ans=1;
    for(;b;b>>=1,a=mul(a,a))
        if(b&1) ans=mul(ans,a);
    return ans;
}
IN void upd(int&a,int b){
    a=add(a,b);
}

CO int N=500+10;
int pw[N],pst,pcir;
int bas[N],bst,bcir;
LL cnt[N];
int dp[N][10][N];

CO int inv[10]={1,1,500000004,333333336,250000002,400000003,166666668,142857144,125000001,111111112,};
IN int binom(LL n,int m){
    if(m==0) return 1;
    if(n();
//  int d=read();
//  int ans=IncreasingNumber::countNumbers(n,d);
//  printf("%d\n",ans);
//}

话说Topcoder让你实现一个类,我没看出这样做有什么好处。Z前辈告诉我这样大概不用消除了读入时间的影响?

开始我的程序漏洞百出,最后写了个对拍才调出来。

暴力DP程序:

CO int N=500+10;
int f[N][N][N];

int main(){
    int n=read(),d=read();
    f[0][1][0]=1;
    for(int i=0;i

对拍程序:

int main(){
    for(int i=3;i<=18;++i)
        for(int j=1;j<=500;++j){
            cerr<<"T "< std.out");
            system("test.exe < std.in > test.out");
            if(system("fc std.out test.out")) return 1;
        }
    return 0;
}

我发现如果直接freopen的话system的调用会失效。

注意那个fflush。我发现如果把造数据和对拍写在一起,就是又有输出又有调用其他程序的话,在输出和调用之间会卡住。这时候需要加个cerr或者fflush刷新一下。

你可能感兴趣的:(Topcoder10566 IncreasingNumber)