題意:
1..n的數中數字包含‘13’且能被13整除的,有多少個。n<10^9
分析:
按位DP
困在能被13整除上了,查了能被13整除的數的特性,不知道怎麼轉化dp...
後來看了解題報告,狀態上多記錄個模13的餘數就好了~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ans;
int num[10], ln;
int f[10][13][3];
void NtoNum(int *num, int &ln, int n){
ln = 0;
while(n){
num[++ln] = n % 10;
n = n / 10;
}
}
int dfs(int cur, int pre, int mod, bool apr, bool flag){
int i, ret, high;
if (cur <= 0) return apr && mod == 0;
if (!flag && apr && ~f[cur][mod][2]) return f[cur][mod][2];
if (!flag && !apr && pre != 1 && ~f[cur][mod][1]) return f[cur][mod][1];
if (!flag && !apr && pre == 1 && ~f[cur][mod][0]) return f[cur][mod][0];
high = flag ? num[cur] : 9;
ret = 0;
for (i = 0; i <= high; i++){
ret += dfs(cur - 1, i, (mod * 10 + i) % 13, apr || (pre == 1 && i == 3), flag && (i == high));
}
if (!flag){
if (pre == 1 && !apr) f[cur][mod][0] = ret;
if (pre != 1 && !apr) f[cur][mod][1] = ret;
if (apr) f[cur][mod][2] = ret;
}
return ret;
}
int main(){
int n;
while(scanf("%d",&n) != EOF){
ans = 0;
NtoNum(num, ln, n);
memset(f, 0xff, sizeof(f));
ans = dfs(ln, 0, 0, false, true);
printf("%d\n", ans);
}
return 0;
}
/*
f[i][k][0] 不含13,不以1結尾
f[i][k][1] 不含13,以1結尾
f[i][k][2] 含13
f[i + 1][(k * 10 + num) % 13][0] += f[i][k][0], num != 1
f[i + 1][(k * 10 + 1) % 13][0] += f[i][k][1], num != 1, 3
f[i + 1][(k * 10 + 1) % 13][1] += f[i][k][0] + f[i][k][1]
f[i + 1][(k * 10 + num) % 13][2] += f[i][k][2]
f[i + 1][(k * 10 + 3) % 13][2] += f[i][k][1]
其實又用記憶化搜索實現的。。。1A哦~寫完就A了的哦~哈哈~~
還是記憶化搜索實現簡單。。。
總結經驗,記錄dfs時,不一定要開和參數一樣的數組,
適當變換下,分成幾種情況開多個數組,可以節省下內存
46ms 196k
就是慢點...
*/