【[AHOI2009]同类分布】

这是一篇有些赖皮的题解

(如果不赖皮的话,bzoj上也是能卡过去的)

首先由于我这个非常\(sb\)的方法复杂度高达\(O(171^4)\),所以面对极限的\(1e18\)的数据实在是卡死了

但是这个时候可以骗一下

一般来说肯定会有一个点的数据到达了\(1e18\),所以我们先将\(1\)\(1e18\)之间的答案算出来,这样再去算另一个左边界的话至少可以节省一半的常数,就算左边界不是很小也有可能还算点希望

如果左边界特别小的话,可能就能幸运的卡过去

这道题的左边界就非常小啊,我估计不超过\(1e6\)

于是就卡过去了

再来看看我这个非常\(sb\)的dp,我觉得可能没有人这么写

我们设\(dp[i][j][s][k]\)表示一个数填到了\(i\)位,最高位填的是\(j\),数位和是\(s\),且这些数中对于某一个数取模得\(k\)的数的个数

至于这个某一个数是什么,我们当然是要最外面套上一个枚举数位和了

那么答案很简单啊,如果我们当前枚举的数位和是\(x\)的话,答案肯定就跟\(dp[][][x][0]\)有关系了

那么这个方程怎么转移呢

显然有

\[dp[i+1][p][j+p][(p*10^i+k)\%x]=\sum_{t=0}^9dp[i][t][j][k]\]

\(t\)表示上一位填的数,\(i\)是位数,\(p\)是这一位填的数,\(j\)是数位和,\(k\)是对当前枚举的数位和取模之后的值,\(x\)表示当前枚举的数位和

同时我们发现好像直接去枚举\(t\)有些奢侈,我们可以直接把\(\sum_{t=0}^9dp[i][t][j][k]\)算好,于是我用\(dp[i][10][j][t]\)来存下来\(\sum_{t=0}^9dp[i][t][j][k]\),这样就可以优化转移了

之后就是数位\(dp\)的套路卡上界了,大概就是注意一下卡上界的时候存一下前面的数位和

复杂度大概是\(O((log_{10}n*9)^4)\),确实这是一个很垃圾的复杂度

代码

#include
#include
#include
#define re register
#define maxn 172
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
LL dp[20][11][maxn][maxn];
LL L,R;
LL ans;
int num[2],a[20][2];
LL base[20];
LL mod;
inline LL qm(LL x) {return x>=mod?x-mod:x;}//优化一下取模
inline void spilt(LL x,int pd)
{
    num[pd]=0;
    while(x) a[++num[pd]][pd]=x%10,x/=10;
}//分解数位
inline void work(int x,int Len)
{
    mod=x;
    memset(dp,0,sizeof(dp));
    for(re int i=0;i<=9;++i)
        dp[1][i][i][qm(i)]+=1,dp[1][10][i][qm(i)]+=1;
    for(re int i=1;i

你可能感兴趣的:(【[AHOI2009]同类分布】)