[BZOJ1799] [AHOI2009] 同類分佈 [數位dp]
阿新 • • 發佈:2018-10-31
[a,b]滿足f(i)的數字個數;f(i)與數位相關。考慮數位dp。
簡單想法是傳當前確定的數位和、還有當前確定的那一部分原數就好了。
然而第一個就算了,第二個根本放不下(不放數組裡面的話只靠第一個確定不了狀態)
回到問題來。只是“整除”可能有點模糊?
[a,b]中,被自身各數位和整除的數字個數
這麼考慮呢?
發現什麼了嗎?對了,mod。
考慮把相對較小的餘數和模數儲存進來,這樣的話狀態是:
f(pos,sum,mod,remainder)
其中pos≤18, sum≤162, mod≤162, remainder<162……是不是有點大?
好像這個爆了空間。時間勉勉強強吧,在能過和不能過中間徘徊。
好像font就是mod,能不能合併哇?
這樣的話就變成了算到pos位,%mod=remainder。要求最後sum=mod。
而且這樣正好能夠保證原數被狀態唯一確定。
注意這樣的話有一個mod沒有被記錄進去,然而mod不同,f也不同。所以每次memset。
實際上這樣並沒有在時間上合併sum和mod,不過至少空間能過了。時間就卡一卡吧。
記憶化搜尋的關係,多剪一下枝的話跑起來估計還勉強吧?
就是不知道kpm是咋整的能卡到1000ms
Accepted 5272ms
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
using namespace std;
long long a,b;
int bit[20];
long long F[20][165][165];
long long dfs(const int &pos, const int &sum, const int &mod, const int &remainder, const bool &limit) {
if(sum - pos * 9 > 0) return 0;
if(!pos && !sum) return !remainder;
if(!limit && F[pos][sum][remainder] != -1) return F[pos][sum][remainder];
int up = limit ? bit[pos] : 9;
if(sum < up) up = sum;
long long ret = 0;
for(int t, i = 0; i <= up; ++i) {
ret += dfs(pos - 1, sum - i, mod, (remainder * 10 + i) % mod, limit && i == up);
}
if(!limit) F[pos][sum][remainder] = ret;
return ret;
}
long long solve(long long &x) {
bit[0] = 0;
while(x) {
bit[++bit[0]] = int(x % 10);
x /= 10;
}
long long ret = 0;
for(int i = 1; i <= 9 * bit[0]; ++i) {
memset(F, -1, sizeof(F));
ret += dfs(bit[0], i, i, 0, true);
}
return ret;
}
int main() {
scanf("%lld%lld", &a, &b);
printf("%lld", solve(b) - solve(--a));
return 0;
}