[SCOI2009]windy数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SCOI2009]windy数相关的知识,希望对你有一定的参考价值。
哎。。。我最讨厌数位DP。。写了这么长调完了。
主要是注意可以取得区间的处理问题以及边界。。挂了好久
代码长,写的丑,不要喷
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define lld long long using namespace std; lld mabs(lld x){ if(x < 0){ return -x; } return x; } lld a,b; int getlen(lld x){ int cnt = 0; while(x){ cnt++; x /= 10; } return cnt; } void geti(lld x,lld len,int* haha){ while(x){ haha[len--] = x % 10; x /= 10; } } lld dp[20][10]; lld sdp[20][10]; int tmp1[20]; int tmp2[20]; void ini(){ for(int i = 0;i<=9;i++){ dp[1][i] = 1; sdp[1][i] = i+1; } for(int i = 2;i<=20;i++){ for(int j = 0;j<=9;j++){ if(j >= 2){ dp[i][j] += sdp[i-1][j-2]; } if(j <= 7){ dp[i][j] += sdp[i-1][9] - sdp[i-1][j+1]; } } sdp[i][0] = dp[i][0]; for(int j = 1;j<=9;j++){ sdp[i][j] = sdp[i][j-1] + dp[i][j]; } } } int llen; int slove1(int now,int type){ if(now == llen+1){ return 1; } if(type == 1){ lld tmpans = 0; int ul = max(tmp1[now-1] +2,tmp1[now]); int dl = tmp1[now-1] -2; if(ul <= 9){ tmpans += sdp[llen-now+1][9]-sdp[llen-now+1][ul-1]; } if(ul == tmp1[now]){ tmpans -= dp[llen-now+1][tmp1[now]]; } if(dl >= tmp1[now]){ tmpans += sdp[llen-now+1][dl]-(sdp[llen-now+1][tmp1[now]]); } if(tmp1[now] >= ul || tmp1[now] <= dl){ tmpans += slove1(now+1,1); } return tmpans; } else if(type == 2){ lld tmpans = 0; int ul = tmp2[now-1]+2; int dl = min(tmp2[now],tmp2[now-1] -2); if(ul <= tmp2[now]){ tmpans += sdp[llen-now+1][tmp2[now]-1]-sdp[llen-now+1][ul-1]; } if(dl >= 0){ tmpans += sdp[llen-now+1][dl]; } if(dl == tmp2[now]){ tmpans -= dp[llen-now+1][tmp2[now]]; } if(tmp2[now] >= ul || tmp2[now] <= dl){ tmpans += slove1(now+1,2); } return tmpans; } else{ if(tmp2[now] == tmp1[now]){ if(now == 1 || mabs(tmp1[now-1]-tmp1[now]) >= 2){ return slove1(now+1,0); } return 0; } else{ lld tmpans = 0; if(now == 1){ return sdp[llen-now+1][tmp2[now]-1] - sdp[llen-now+1][tmp1[now]]+slove1(now+1,1)+slove1(now+1,2); } int ul = tmp1[now-1] +2; int dl = tmp2[now-1] -2; if(tmp2[now] >= ul){ if(tmp1[now] >= ul){ return sdp[llen-now+1][tmp2[now]-1]-sdp[llen-now+1][tmp1[now]]+slove1(now+1,1)+slove1(now+1,2); } else{ return sdp[llen-now+1][tmp2[now]-1]-sdp[llen-now+1][ul-1]+slove1(now+1,2); } } if(tmp1[now] <= dl){ if(tmp2[now]<=dl){ return sdp[llen-now+1][tmp2[now]-1]-sdp[llen-now+1][tmp1[now]]+slove1(now+1,1)+slove1(now+1,2); } else{ return sdp[llen-now+1][dl]-sdp[llen-now+1][tmp1[now]]+slove1(now+1,1); } } return 0; } } } int slove(lld bgin,lld end,lld len){ geti(bgin,len,tmp1); geti(end,len,tmp2); llen = len; return slove1(1,0); } lld anss = 0; int main(){ freopen("1.in","r",stdin); freopen("my.out","w",stdout); ini(); scanf("%lld %lld",&a,&b); int len1 = getlen(a); int len2 = getlen(b); if(len1 != len2){ anss += slove(a,pow(10,len1)-1,len1); len1++; while(len1 < len2){ anss += slove(pow(10,len1-1),pow(10,len1)-1,len1); len1++; } anss += slove(pow(10,len1-1),b,len1); } else{ anss = slove(a,b,len1); } printf("%lld\n",anss); return 0; }
主要思路:裸的数位DP。。但是细节很多。。
dp[i][j]:长度为i的数字第一位是j(每一位均可取0-9,可以有前导0)的符合题意的数字个数。
sdp[i][j]:对每一个i的dp[i][j]的前缀和;在slove1会用到;
我把[a,b]的区间分成了[a,x1],[x1+1,x2],.....[xn,b];这些保证区间首尾数的位数相等的子区间分别求然后加起来。
一定考虑好区间的交并问题。。。
以上是关于[SCOI2009]windy数的主要内容,如果未能解决你的问题,请参考以下文章