sgu 390 购票(上下界数位dp)
2016-11-08 17:05
369 查看
有一位售票员给乘客售票。对于每位乘客,他会卖出多张连续的票,直到已卖出的票的编号的数位之和不小于给定的正数K。然后他会按照相同的规则给下一位乘客售票。
初始时,售票员持有的票的编号是从L到R的连续整数。请你求出,售票员可以售票给多少位乘客。
数据规模:1 ≤ L ≤ R ≤ 10^18,1 ≤ K ≤ 1000。
思路:
此题需要上下界进行数位dp,且需要从小的开始放
dp[i][j][k]表示前面i位,现在前面的和,已经有的值
初始时,售票员持有的票的编号是从L到R的连续整数。请你求出,售票员可以售票给多少位乘客。
数据规模:1 ≤ L ≤ R ≤ 10^18,1 ≤ K ≤ 1000。
思路:
此题需要上下界进行数位dp,且需要从小的开始放
dp[i][j][k]表示前面i位,现在前面的和,已经有的值
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int dig[2][20],k; bool vis[2][2][20][200][1010]; struct node{ long long Count,left; }dp[2][2][20][200][1010]; void add(node &x,node y){ x.Count+=y.Count; x.left=y.left; } node dfs(int pos,int limit1,int limit2,int pre_sum,int sum){ if(pos==-1) return sum+pre_sum>=k ? (node){1,0}:node{0,sum+pre_sum}; if(vis[limit1][limit2][pos][pre_sum][sum]==1) return dp[limit1][limit2][pos][pre_sum][sum]; node ans={0,sum}; int low=(limit1==1 ? dig[0][pos]:0),high=(limit2==1 ? dig[1][pos]:9); for(int i=low;i<=high;i++) add(ans,dfs(pos-1,limit1&(i==low),limit2&(i==high),i+pre_sum,ans.left)); vis[limit1][limit2][pos][pre_sum][sum]=1,dp[limit1][limit2][pos][pre_sum][sum]=ans; return ans; } int solve(int i,long long x){ int len=0; while(x){ dig[i][len++]=x%10; x/=10; } return len; } int main(){ long long L,R; scanf("%lld%lld%d",&L,&R,&k); solve(0,L); int len=solve(1,R); printf("%lld\n",dfs(len-1,1,1,0,0).Count); }
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int dig[2][20],k; bool vis[20][200][1010]; struct node{ long long Count,left; }dp[20][200][1010]; void add(node &x,node y){ x.Count+=y.Count; x.left=y.left; } node dfs(int pos,int limit1,int limit2,int pre_sum,int sum){ if(pos==-1) return sum+pre_sum>=k ? (node){1,0}:node{0,sum+pre_sum}; if(!limit1&&!limit2&&vis[pos][pre_sum][sum]==1) return dp[pos][pre_sum][sum]; node ans={0,sum}; int low=(limit1==1 ? dig[0][pos]:0),high=(limit2==1 ? dig[1][pos]:9); for(int i=low;i<=high;i++) add(ans,dfs(pos-1,limit1&(i==low),limit2&(i==high),i+pre_sum,ans.left)); if(!limit1&&!limit2) vis[pos][pre_sum][sum]=1,dp[pos][pre_sum][sum]=ans; return ans; } int solve(int i,long long x){ int len=0; while(x){ dig[i][len++]=x%10; x/=10; } return len; } int main(){ long long L,R; scanf("%lld%lld%d",&L,&R,&k); solve(0,L); int len=solve(1,R); printf("%lld\n",dfs(len-1,1,1,0,0).Count); }
相关文章推荐
- SGU 390 Tickets (数位dp,k进制树的合并)
- SGU 390 Tickets(数位DP)
- SGU 390-Tickets(数位dp)
- SGU 390 Tickets (数位DP, k进制树)
- 【SGU 390】Tickets (数位DP)
- SGU_390_Tickets(另类数位DP)
- SGU_390_Tickets(另类数位DP)
- SGU 365 Ships of the Desert 简单数位dp
- SGU 492 经典数位dp
- 数位统计 sgu 390 <浅谈数位类问题>
- 【数位DP】【SGU 258】. Almost Lucky Numbers
- SGU 258 Almost Lucky Numbers 接近幸运数(数位DP)
- hdu 3555(数位dp)
- HDUOJ 2089 数位DP
- SGU 365 Ships of the Desert dp
- ACDream 1064——完美数(数位DP)
- hdu3555 Bomb ——数位DP入门题
- 【BZOJ 1026】【SCOI2009】[数位dp]windy数
- 【BZOJ 3329】[数位dp]Xorequ
- hdu 5564 Clarke and digits 矩阵快速幂优化数位dp