您的位置:首页 > 其它

CodeForces 215E Periodical Numbers 数位DP

2014-08-06 10:39 417 查看
这题做了有好几天了,终于过了= =

完全不懂网上题解的递推写法,只能自己用记忆化搜索瞎搞,总算是搞出来了。

具体策略就是记忆化搜索的时候用一个tmp数组记录最前面len个的值,然后后面的数字必须要和前len相同。

但是麻烦的是这样子会有重复,想了一个很挫的写法就是枚举算出恰好长度为ll并且循环节长度为l的数字的个数,然后全部记录下来,从小到大依次减去重复的。

真是挫。。。sad

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <string>
#include <iostream>
#include <map>
#include <cstdlib>
#include <list>
#include <set>
#include <queue>
#include <stack>

using namespace std;

typedef long long LL;
const int maxn = 70;
int lim[maxn],len;
int tmp[maxn];
LL f[maxn][maxn];

void getlim(LL num) {
len = 0;
memset(lim,0,sizeof(lim));
while(num) {
lim[len++] = num % 2;
num /= 2;
}
}

LL dfs(int now,int l,int ll,int first,int bound) {
if(now == 0) {
return first % l == 0 && first / l >= 2 && first == ll;
}
int m = bound ? lim[now - 1] : 1;
if(first != -1 && !bound && f[now][first] != -1) return f[now][first] ;
LL ret = 0;
for(int i = 0;i <= m;i++) {
if(i && first == -1) first = now;
if(first == -1) ret += dfs(now - 1,l,ll,-1,bound && i == m);
else {
int pos = first - now;
tmp[pos] = i;
if(pos < l) ret += dfs(now - 1,l,ll,first,bound && i == m);
else if(tmp[pos % l] == i) {
ret += dfs(now - 1,l,ll,first,bound && i == m);
}
}
}
if(first != -1 && !bound) f[now][first] = ret;
return ret;
}

LL solve(LL num) {
getlim(num);
LL ret = 0,cnt[maxn][maxn];
memset(cnt,0,sizeof(cnt));
for(int i = 1;i <= len / 2 + 1;i++) {
for(int j = len;j >= 1;j--) {
memset(f,-1,sizeof(f));
cnt[i][j] = dfs(len,i,j,-1,1);
}
}
for(int i = 2;i <= len / 2;i++) {
for(int j = 1;j < i;j++) if(i % j == 0) {
for(int k = i * 2;k <= len;k++) if(k % i == 0) {
cnt[i][k] -= cnt[j][k];
}
}
}
for(int i = 1;i <= len / 2;i++) {
for(int j = 1;j <= len;j++) {
ret += cnt[i][j];
}
}
return ret;
}

int main() {
LL a,b; cin >> a >> b;
cout << solve(b) - solve(a - 1) << endl;
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: