【数位DP】ZOJ2599Graduated Lexicographical Ordering
来源:互联网 发布:淘宝客服周总结报告 编辑:程序博客网 时间:2024/06/05 11:40
传送门
Time Limit:10S Memory Limit:32768KB
Description
我们定义一种独特的给数排序的方法:
对于两个数,数码和较小的排在前面。因此
现在给你
多组测试数据。
Input
若干行。每一行两个数
Output
每一行两个数即两问的答案。
Sample Input
Sample Output
一道很恶心的数位DP 555~
先考虑第一问。可以通过DP求出数位之和比
对于第二问,已经知道了对于每一个数位和的个数就可以确定第
事实上这些都是很好想的,就是代码不太好写。
#include <iostream>#include <cstdio>#define LL long long intusing namespace std;LL n, k, dp[20][205];//数位之和是sum且有pos位的数的个数LL dfs(int pos,int sum){ if(sum>9*pos||sum<0||pos<0)return 0; if(!pos&&!sum)return 1; if(dp[pos][sum])return dp[pos][sum]; LL &ans=dp[pos][sum]; for(int i=0;i<10&&i<=sum;++i) ans+=dfs(pos-1,sum-i); return ans;}//计算1~n中数位之和是sum的个数LL dfs2(LL n,int sum){ int tmp[20], len=0; while(n) { tmp[len++]=n%10; n/=10; } LL ans=0; for(int i=len-1;~i;--i) for(int j=0;j<tmp[i];++j) ans+=dfs(i,sum--);//从高位到低位枚举每一位的数字,同时数位之和减少 ans+=dfs(0,sum);//如果n的数位之和也是sum,就在这里+1 return ans;}//求n的数位之和int getsum(LL n){ int ans=0; while(n)ans+=n%10, n/=10; return ans;}//求前缀为pre、数位之和为sum且在1~n之间的数的个数LL ask_pre(LL n,LL pre,int sum){ LL ans=0; int w[20], w2[20], len=0, len2=0; while(n){w[len++]=n%10;n/=10;} while(pre){w2[len2++]=pre%10;sum-=w2[len2-1];pre/=10;} for(int i=0;i+i<len;++i)swap(w[i],w[len-i-1]); for(int i=0;i+i<len2;++i)swap(w2[i],w2[len2-i-1]); for(int i=0;i<len2;++i) if(w[i]!=w2[i]) { if(w[i]<w2[i])--len; for(int j=len-len2;~j;--j) ans+=dfs(j,sum); return ans; } //说明前缀pre是n的前缀,那么就统计后面的位上能产生的个数 LL tmp=0; for(int i=len2;i<len;++i)tmp=tmp*10+w[i]; ans+=dfs2(tmp,sum); for(int i=len-len2-1;~i;--i)ans+=dfs(i,sum); return ans;}//求字典序比k小的、数位之和为sum且1~n之间的数的个数LL query(LL n,LL k,int sum){ int w[20], len=0; LL ans=0, pre=1; while(k) { w[len++]=k%10; k/=10; } for(int i=len-1, b=1;~i;--i) { for(int j=b;j<w[i];++j)ans+=ask_pre(n,pre++,sum); b=0; pre*=10; } for(int i=0;i<len;++i) if(w[i]==0)++ans; else break; return ans;}//求第一问的答案LL ans1(LL n,LL k){ int sum=getsum(k); LL ans=1; for(int i=1;i<sum;++i)ans+=dfs2(n,i); return ans+query(n,k,sum);}//求第二问的答案LL ans2(LL n,LL k){ int sum=1; LL tmp; while((tmp=dfs2(n,sum))<k) k-=tmp, ++sum; LL pre=1;int pre_sum=1; while(1) { while((tmp=ask_pre(n,pre,sum))<k) { k-=tmp; ++pre, ++pre_sum; } if(pre_sum==sum)break; pre*=10; } while(--k)pre*=10; return pre;}int main(){ while(~scanf("%lld%lld",&n,&k)&&n) printf("%lld %lld\n",ans1(n,k),ans2(n,k)); return 0;}
0 0
- 【数位DP】ZOJ2599Graduated Lexicographical Ordering
- ZOJ2599:Graduated Lexicographical Ordering(非常经典的数位DP)
- 数位dp
- 数位DP
- 数位DP
- 数位dp
- 数位dp
- 数位dp
- 数位DP
- 数位dp
- 数位DP
- 【数位DP】
- 数位DP
- 数位dp
- 数位dp
- 数位DP
- 数位DP
- 数位dp
- ProgressDialog的简单应用
- MySQL创建用户与授权方法
- 软件测试工具LoadRunner脚本回放问题及解决
- GitHub for Windows 安装
- 关于淘宝开放平台API的session失效问题解决
- 【数位DP】ZOJ2599Graduated Lexicographical Ordering
- [破解实例][OllyDbg] CrackMe005-ajj.2
- iOS 自定义弹窗UIAlertView —— HERO博客
- 五大角色和主域控制器
- Centos下安装Scrapy
- 17. Letter Combinations of a Phone Number
- 三目运算符在C语音和C++语言中的区别
- PHP 安装包依赖关系管理工具Composer
- JAVA_构造函数重载 OverloadingConstructors.java