CodeForces 915C [DFS] CodeForces 158E [DP]
2018-01-28 01:21
423 查看
CodeForces 915C Permute Digits
http://codeforces.com/problemset/problem/915/CProblem Description
You are given two positive integer numbers a and b. Permute (change order) of the digits of a to construct maximal number not exceeding b. No number in input and/or output can start with the digit 0.It is allowed to leave a as it is.
Input
The first line contains integer a (1 ≤ a ≤ 1018). The second line contains integer b (1 ≤ b ≤ 1018). Numbers don’t have leading zeroes. It is guaranteed that answer exists.Output
Print the maximum possible number that is a permutation of digits of a and is not greater than b. The answer can’t have any leading zeroes. It is guaranteed that the answer exists.The number in the output should have exactly the same length as number a. It should be a permutation of digits of a.
Examples
input 1
123222
output 1
213input 2
392110000
output 2
9321input 3
49405000
output 3
4940中文大意
已知a,b两个数,求将a的各个数码重排后,能得出的不大于b的最大数。a,b不超过18位,且a可以不变。分析
首先想到,只需保存a中0~9的数码个数。如果a的位数比b少,直接输出最大可能的a,因为无论其数字位置变化,都有a<ba<b。对于a,b位数一样的情况,我们一位一位的分析。为保证 a 与 b 最接近,高位一定是尽量取得与 b 一样。因此首先考虑对于倒数第 i 位数(从最高位数起的第 i 位)而a,b,前面的数码都一模一样。此时如果在 a 使用了前面位数的数字后仍然剩下数码 x,且 x 与 b 的第 i 位相等,在这种情况下,为了保证 a<=ba<=b 那么我们先暂时取该位就为 x。 因为前面的数码都一样,我们只用考虑后面能不能得到一个数串使得i位后面的a不比i位后面的b大。怎么判断呢?如果出现一个局面,在取到第j位时,使得a剩下可取的数都比b的第j位数码大,那么这样就一定不能满足题目要求。假如出现这种局面,我们需要返回到前面最近的,且这一位中有剩余数码x,使得x比b的该位小,而我们不得不放弃之前取的与b相同的数码,改为这个数码x,这样后面的位数无论如何取,都有a<ba<b 了,于是后面就改成可以取的最大数即可。
描述很复杂,实际操作就是用一个bool dfs, 保存局面,然后先看a在该位能否取得与b一样,如果a没有等于b该位的数,且有至少一个小于b该位的数,那么一定行,就直接打印前面与b一样,后面为剩下的最大数串,并返回true。如果a没有小于等于b该位的数可取,那一定不行,返回false。若a可以取得与b该位一样的数,那么先看能不能取一样,如果返回false,则改取得最大的且小于b该位的数,如果有,输出结果,没有就再返回false。
总结
这个题反正方法比较简单,只是有些特判不能忘记,还有就是题上说了,保证有答案。这个题tag的是dp,大概是有问题吧,不用保存状态,也不会重复取,哪来的动态规划?
在测试程序时,可以用以下几组数据来测:
input
43224321
output
4232input
1000010000
output
10000参考代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int d[15],b[25],lena,lenb,res[25]; void solve1() { for(int i=9;i>=0;i--) while(d[i]--) printf("%d",i); } bool f(int digit[15],int cur) { if(cur>lenb) { for(int i=1;i<cur;i++) printf("%d",res[i]); return true; } if(digit[b[cur]]) { digit[b[cur]]--; res[cur]=b[cur]; if(f(digit,cur+1)) return true; digit[b[cur]]++; } bool flag=false; for(int i=b[cur]-1;i>=0;i--) if(digit[i]) { flag=true; res[cur]=i; digit[i]--; break; } if(flag) { for(int i=1;i<=cur;i++) printf("%d",res[i]); for(int i=9;i>=0;i--) while(digit[i]--) printf("%d",i); return true; } return false; } int main() { char a; while((a=getchar())>='0') d[a-48]++,lena++; while((a=getchar())>='0') b[++lenb]=a-48; if(lenb>lena) solve1(); else f(d,1); printf("\n"); }
下面一道真正的dp题。
CodeForces 158E Phone Talks
http://codeforces.com/problemset/problem/158/EProblem Description
Cool J has recently become a businessman Mr. Jackson, and he has to make a lot of phone calls now. Today he has n calls planned. For each call we know the moment ti (in seconds since the start of the day) when it is scheduled to start and its duration di (in seconds). All ti are different. Mr. Jackson is a very important person, so he never dials anybody himself, all calls will be incoming.Mr. Jackson isn’t Caesar and he can’t do several things at once. If somebody calls him while he hasn’t finished the previous conversation, Mr. Jackson puts the new call on hold in the queue. In this case immediately after the end of the current call Mr. Jackson takes the earliest incoming call from the queue and starts the conversation. If Mr. Jackson started the call at the second t, and the call continues for d seconds, then Mr. Jackson is busy at seconds t, t + 1, …, t + d - 1, and he can start a new call at second t + d. Note that if Mr. Jackson is not busy talking when somebody calls, he can’t put this call on hold.
Mr. Jackson isn’t Napoleon either, he likes to sleep. So sometimes he allows himself the luxury of ignoring a call, as if it never was scheduled. He can ignore at most k calls. Note that a call which comes while he is busy talking can be ignored as well.
What is the maximum number of seconds Mr. Jackson can sleep today, assuming that he can choose an arbitrary continuous time segment from the current day (that is, with seconds from the 1-st to the 86400-th, inclusive) when he is not busy talking?
Note that some calls can be continued or postponed to the next day or even later. However, the interval for sleep should be completely within the current day.
Input
The first input line contains a pair of integers n, k (0 ≤ k ≤ n ≤ 4000) separated by a space. Following n lines contain the description of calls for today. The description of each call is located on the single line and consists of two space-separated integers ti and di, (1 ≤ ti, di ≤ 86400). All ti are distinct, the calls are given in the order of strict increasing ti.Scheduled times of calls [ti, ti + di - 1] can arbitrarily intersect.
Output
Print a number from 0 to 86400, inclusive — the maximally possible number of seconds for Mr. Jackson to sleep today.Examples
input
3 230000 15000
40000 15000
50000 15000
output
49999input
5 11 20000
10000 10000
20000 20000
25000 10000
80000 60000
output
39999Note
In the first sample the most convenient way is to ignore the first two calls.In the second sample it is best to ignore the third call. In this case Mr. Jackson will have been speaking:
first call: from 1-st to 20000-th second,
second call: from 20001-st to 30000-th second,
fourth call: from 30001-st to 40000-th second (the third call is ignored),
fifth call: from 80000-th to 139999-th second.
Thus, the longest period of free time is from the 40001-th to the 79999-th second.
中文大意
J有n个电话要接,每个电话打进来的时刻为第t[i]分钟,时长为d[i]分钟。每一个电话打进来时,J有两种选择:
1.将电话挂掉(最多挂k次,不占时间)
2.接听(如果当时正在打其他电话,则这个电话加入等待队列,等上一个电话打完后立马接听)
时间从第1秒开始算,一直到86400秒结束,问你能够他能获得的最长连续间隔为多长时间。
分析
首先,很显然一定要挂k次才优。简单证明就是,如果挂k-1次比挂k次还优,那若在挂k-1的基础上再挂一次任意一个电话,一定有Ansk−1>=AnskAnsk−1>=Ansk,那肯定挂得越多越好,至于怎么挂最好,后面再讨论。
要使得空当最大,如果空当过后就是接听第 i 个电话,空当时间为Starti−Endi−1Starti−Endi−1 这个 StartiStarti 有两种情况,要么等于aiai,要么大于aiai,而如果大于aiai就是说没有i-1与i没有空当,那就与假设矛盾了,所以这里的StartiStarti一定等于aiai,而aiai,如果打了这个电话,就一定不变,如果挂掉,则与假设空当过后接的第一个电话矛盾,那么这个 StartiStarti是没法变了,变的只能是Endi−1Endi−1。要使空当最大,那Endi−1Endi−1不可避免地就要尽量小。
因此设dp[i][j] 为完成第i个电话,挂掉了j个电话的最短时间,最后求一个Max(ai−dp[i−1][k]−1)Max(ai−dp[i−1][k]−1)就完了(减1是因为aiai时刻在打电话,不能算入空当)。
那dp方程就变得简单
对于dp[i][j],状态有两种:
1.挂掉第i个电话,用去一次机会,那dp[i][j]=dp[i−1][j−1]dp[i][j]=dp[i−1][j−1],意思就是说相当于完成上一个电话的最短时间
2.不挂掉第i个电话,打完这个电话,那dp[i][j]=max(dp[i−1][j]+1,a[i])+d[i]dp[i][j]=max(dp[i−1][j]+1,a[i])+d[i],取max是因为有可能i 这个电话是在队列里,如果是的话就直接接听(+1是因为接听是从新的一秒开始算),不是就等到它打进来。
所以最终dp[i][j]=min(dp[i−1][j−1],max(dp[i−1][j]+1,a[i])+d[i])dp[i][j]=min(dp[i−1][j−1],max(dp[i−1][j]+1,a[i])+d[i])
最后再用前面说的Max(ai−dp[i−1][k]−1)Max(ai−dp[i−1][k]−1)遍历一遍算结果就好
总结
这道题解决方法其实很巧妙,而注意点就是记得最后我们为了方便计算,假设在第86401秒打了一个持续0秒的电话。(一定是从86401,而不是86400开始打,不然就会多占一秒)还有就是特判不能少,比如当k==n就直接输出86400。参考代码
#include<cstdio> using namespace std; int N,K,a[4005],d[4005],f[4005][4005],ans; int main() { scanf("%d%d",&N,&K); for(int i=1;i<=N;i++) scanf("%d%d",&a[i],&d[i]); a[N+1]=86401;//一定是86401 if(N==K) ans=86400;//特判 else for(int i=1;i<=N;i++) { f[i][0]=max(f[i-1][0]+d[i],a[i]+d[i]-1); for(int j=1;j<=K&&j<=i;j++) f[i][j]=min(max(f[i-1][j]+d[i],a[i]+d[i]-1),f[i-1][j-1]); ans=max(ans,a[i+1]-f[i][K]-1);//边算边直接求答案 } ans=max(ans,a[1]-1); printf("%d\n",ans); return 0; }
P.S. AFO过后已经一年没碰OI了,真的是一点都没碰,这一年除了浅学了Python 和 Java 什么都没干,而且最后发现还是C++亲切。
P.P.S. 以后将尽量提供英文版解析。
相关文章推荐
- codeforces 158E Phone Talks (dp)
- Codeforces 337 D Book of Evil(树形dp,两遍dfs)
- CodeForces - 915C Permute Digits (dfs)
- codeforces 158E. Phone Talks(dp)
- Codeforces 467D. Fedor and Essay (Graphs,dfs,dp,hashing,strings,图论综合型好题)
- CodeForces 149D 括号染色问题 dp+dfs好题
- codeforces 280c 概率dp + dfs
- CodeForces 258 B.Little Elephant and Elections(数位DP+dfs)
- codeforces 132C Logo Turtle dp DFS 搜索答案
- codeforces 915C Permute Digits (DFS)
- codeforces 55D - Beautiful numbers 数位DP+DFS
- CodeForces 293 B.Distinct Paths(dfs+状压DP)
- codeforces 258B Little Elephant and Elections 数位DP+DFS
- CodeForces - 149D Coloring Brackets 详细题解(递归区间DP+dfs染色,好题)
- CodeForces 148D Bag of mice 概率DP , DFS
- Codeforces 258B. Little Elephant and Elections【数位DP,DFS】
- Codeforces 132C.Logo Turtle【DP,dfs】
- CodeForces - 158E Phone Talks(dp)
- CodeForces - 158E Phone Talks(dp)
- CodeForces 149D Coloring Brackets(区间DP+dfs)