您的位置:首页 > 其它

CodeForces 915C [DFS] CodeForces 158E [DP]

2018-01-28 01:21 423 查看

CodeForces 915C Permute Digits

http://codeforces.com/problemset/problem/915/C

Problem 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

123

222

output 1

213

input 2

3921

10000

output 2

9321

input 3

4940

5000

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

4322

4321

output

4232

input

10000

10000

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/E

Problem 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 2

30000 15000

40000 15000

50000 15000

output

49999

input

5 1

1 20000

10000 10000

20000 20000

25000 10000

80000 60000

output

39999

Note

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. 以后将尽量提供英文版解析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: