昨晚做了一个晚上,自己也举了一些案例都过了,结果一直WA,终于搞定了,这题应该是去年网络赛的题目,有点难,看看其他人都是开三维来做的
这里我是开了 四维,不够简洁,但是我觉得比较好理解,记得曾经某位学长 给我讲题目的时候还 开过六维,
dp[i][j][k][l],i位数j开头是否含有13 k=0?1 (mod) 13的值 l,这个就是DP数组的含义
接下来就是对DP数组的预处理了,由是否还有13和对13取模来进行对第i位的决策
计算过程就是记录当前这一位对13取模的余数是多少 和是否已经含有13,正向处理
#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>
#define ll long long
#define eps 1e-8
#define inf 0xfffffff
//const ll INF = 1ll<<61;
using namespace std;
//vector<pair<int,int> > G;
//typedef pair<int,int > P;
//vector<pair<int,int> > ::iterator iter;
//
//map<ll,int >mp;
//map<ll,int >::iterator p;
int dp[12][12][2][15];//dp[i][j][k][l],i位数j开头是否含有13 k=0?1 (mod) 13的值 l
int num[12];
void clear() {
memset(dp,0,sizeof(dp));
int x = 10;
for(int i=0;i<10;i++)
dp[1][i][0][i] = 1;
for(int i=2;i<=10;i++) {
for(int j=0;j<10;j++) {
for(int k=0;k<10;k++) {
int tmp = (j * x)%13;
for(int l=0;l<13;l++) {
dp[i][j][1][l] += dp[i-1][k][1][(13 - tmp + l)%13];
if(j == 1 && k == 3)
dp[i][j][1][l] += dp[i-1][k][0][(13 - tmp + l)%13];
else
dp[i][j][0][l] += dp[i-1][k][0][(13 - tmp + l)%13];
}
}
}
x *= 10;
}
}
int cal(int x) {
memset(num,0,sizeof(num));
int ans = 0;
int cnt = 0;
int len = 1;
int tmpx = x;
while(tmpx) {
cnt++;
tmpx /= 10;
}
cnt--;
int tmpcnt = cnt;
while(x) {
num[tmpcnt--] = x%10;
x /= 10;
if(x > 0)
len *= 10;
}
int m = 0;
int mark = 0;
for(int i=0;i<=cnt;i++) {
int mod = m%13;
for(int j=0;j<num[i];j++) {
ans += dp[cnt-i+1][j][1][(13-mod)%13];
if((m/len+j)%100 == 13 || mark == 1)
ans += dp[cnt-i+1][j][0][(13-mod)%13];
}
m += num[i]*len;
if((m/len)%100 == 13)
mark = 1;
len /= 10;
}
return ans;
}
int main() {
clear();
int n;
while(scanf("%d",&n) == 1) {
printf("%d\n",cal(n+1));
}
return EXIT_SUCCESS;
}