您的位置:首页 > 其它

Educational Codeforces Round 39 (Rated for Div. 2)(A-D)(水题 + 模拟 + 贪心模拟 + DP)

2018-03-13 14:06 423 查看
昨天用cf的virtual contest开了一场,做的不是特别理想。半个小时A了三题后就一直划水,今天补了D题。

A. PartitionYou are given a sequence a consisting of n integers. You may partition this sequence into two sequences b and c in such a way that every element belongs exactly to one of these sequences.Let B be the sum of elements belonging to b, and C be the sum of elements belonging to c (if some of these sequences is empty, then its sum is 0). What is the maximum possible value of B - C?InputThe first line contains one integer n (1 ≤ n ≤ 100) — the number of elements in a.The second line contains n integers a1, a2, ..., an ( - 100 ≤ ai ≤ 100) — the elements of sequence a.OutputPrint the maximum possible value of B - C, where B is the sum of elements of sequence b, and C is the sum of elements of sequence c.ExamplesinputCopy
3
1 -2 0
output
3
A题:给出含有n个数的数列,问能能否分出两个子序列,使两个子序列中元素的和,相减后最大,最大是多少?子序列可以为空
输入输出的水题,遍历整个数组,正数加,负数减。最后得到的一定最大。
int main() {
int n, sum = 0, num;
scanf("%d", &n);
for(int i=0;i<n;i++){

4000
scanf("%d",&num);
sum += fabs(num);
}
printf("%d\n",sum);

return 0;
}
B. Weird Subtraction ProcessYou have two variables a and b. Consider the following sequence of actions performed with these variables:If a = 0 or b = 0, end the process. Otherwise, go to step 2;
If a ≥ 2·b, then set the value of a to a - 2·b, and repeat step 1. Otherwise, go to step 3;
If b ≥ 2·a, then set the value of b to b - 2·a, and repeat step 1. Otherwise, end the process.
Initially the values of a and b are positive integers, and so the process will be finite.You have to determine the values of a and b after the process ends.InputThe only line of the input contains two integers n and m (1 ≤ n, m ≤ 1018). n is the initial value of variable a, and m is the initial value of variable b.OutputPrint two integers — the values of a and b after the end of the process.ExamplesinputCopy
12 5
output
0 1
B题:给出a,b两个数。并给出操作,如果一个数是另一个数的两倍及以上,就用大数减去小数的两倍。知道一个是0或者不构成两倍关系。一开始的想法是既然是两倍两倍的,那是不是就是每次二分,那是不是就是logn级别的,那1e18的数据量也能过。就又是直接莽了一发模拟。结果TLE。然后想一想因为小数不确定大小,每次并不一定是二分,eg. 1e18  1这两个数每次减2肯定超时。然后就用除法操作优化了一下就过了namespace Solver {
LL a, b;
void solve(){
cin>>a>>b;

while(a && b)
{
if(a/b >= 2)
a -= (a/b)/2*2*b;
else if(b/a >= 2)
b -= (b/a)/2*2*a;
else break;
}
cout<<a<<" "<<b<<endl;
}
};
C. String TransformationYou are given a string s consisting of |s| small english letters.In one move you can replace any character of this string to the next character in alphabetical order (a will be replaced with b, s will be replaced with t, etc.). You cannot replace letter z with any other letter.Your target is to make some number of moves (not necessary minimal) to get string abcdefghijklmnopqrstuvwxyz (english alphabet) as a subsequence. Subsequence of the string is the string that is obtained by deleting characters at some positions. You need to print the string that will be obtained from the given string and will be contain english alphabet as a subsequence or say that it is impossible.
InputThe only one line of the input consisting of the string s consisting of |s| (1 ≤ |s| ≤ 105) small english letters.OutputIf you can get a string that can be obtained from the given string and will contain english alphabet as a subsequence, print it. Otherwise print «-1» (without quotes).ExamplesinputCopy
aacceeggiikkmmooqqssuuwwyy
output
abcdefghijklmnopqrstuvwxyz
C题:给出一个只含有小写字母的串,每个字母可以通过一次操作变成字典序中的下一子母,z不能变。问能否将原串通过这种操作变成一个,含有‘a-z’做子序列的串。
因为我们顺序需要 a-z 而字典序靠后的不能变成前面的字母。那就将我们需要的字母记成p,p从a开始,发现ascall码小于等于p的就改变该字母为p,p++。当z也找到时直接跳出即可。
而这道题当时用google翻译的时候,把105看成了105,数组开小了wa了一发...namespace Solver {
char a[100010];
void solve(){
cin>>a;
int lena = strlen(a);
char p = 'a';
for(int i=0; i<lena; i++)
{
if(p == 'z'+1 ) break;
if(a[i] <= p){
a[i] = p;
p++;
}
}
if(p == 'z'+1) cout<<a<<endl;
else cout<<-1<<endl;
}
};

D. TimetableIvan is a student at Berland State University (BSU). There are n days in Berland week, and each of these days Ivan might have some classes at the university.There are m working hours during each Berland day, and each lesson at the university lasts exactly one hour. If at some day Ivan's first lesson is during i-th hour, and last lesson is during j-th hour, then he spends j - i + 1 hours in the university during this day. If there are no lessons during some day, then Ivan stays at home and therefore spends 0 hours in the university.Ivan doesn't like to spend a lot of time in the university, so he has decided to skip some lessons. He cannot skip more than k lessons during the week. After deciding which lessons he should skip and which he should attend, every day Ivan will enter the university right before the start of the first lesson he does not skip, and leave it after the end of the last lesson he decides to attend. If Ivan skips all lessons during some day, he doesn't go to the university that day at all.Given n, m, k and Ivan's timetable, can you determine the minimum number of hours he has to spend in the university during one week, if he cannot skip more than k lessons?
InputThe first line contains three integers n, m and k (1 ≤ n, m ≤ 500, 0 ≤ k ≤ 500) — the number of days in the Berland week, the number of working hours during each day, and the number of lessons Ivan can skip, respectively.Then n lines follow, i-th line containing a binary string of m characters. If j-th character in i-th line is 1, then Ivan has a lesson on i-th day during j-th hour (if it is 0, there is no such lesson).OutputPrint the minimum number of hours Ivan has to spend in the university during the week if he skips not more than k lessons.ExamplesinputCopy
2 5 1
01001
10110
output
5
D题:一周有n天,每天有m个小时,用01串表示该小时有没有课。每天的第一节课前到校,最后一节课结束后离开。一周可以翘k节课。问一周至少要在学校呆几天。
昨天做这道题的想法是,翘课肯定不会从一天中间的某节课翘课,而是从第一节或者最后一节开始。所以我们一个vector记录每天翘每节课的影响,然后遍历头尾贪心求解。可是这样做的问题是,当翘课数变化时,翘课的方式不具有继承关系。例如110001101,翘两节课肯定是从后往前两节最优,而翘三节课又变成了前三节最优。然后当时就蒙了不知道要怎么做。
今天查了题解才明白过来,这种子结构最优情况的题,第一反应应该就是dp了。我们记dp[i][j]为前i天,翘j节课,呆在学校的最少时间。并且预处理一个数组mm[i][j]表示第i天,翘j节课,呆在学校的最短时间。则,dp[i][j] = min(dp[i-1][j-len] + mm[i][len]); dp可解。namespace Solver {
int n, m, k;
int cnt[maxn];
void solve()
{
memset(mm, INF, sizeof mm);
memset(dp, INF, sizeof dp);
scanf("%d%d%d", &n, &m, &k);
for(int i=0; i<n; i++){
scanf("%s", day);
for(int j=0; j<m; j++)
if(day[j] == '1') v[i].push_back(j);
}

for(int i=0; i<n; i++)
{
if(!v[i].size()){
mm[i][0] = 0;
continue;
}

mm[i][v[i].size()] = 0;
mm[i][0] = v[i][v[i].size()-1] - v[i][0] + 1;
for(int l = 0; l < v[i].size(); l++)
for(int r = l; r < v[i].size(); r++)
{
int att_class = r-l+1; ///参加课程节数
int att_time = v[i][r] - v[i][l] + 1; ///参加课程时间
int kip_class = v[i].size() - att_class; ///跳过课程数

umin(mm[i][kip_class], att_time);
}
}

for(int i=0; i<=v[0].size(); i++)
dp[0][i] = mm[0][i];

for(int i=1; i<n; i++)
{
for(int j=0; j<=k; j++)
{
for(int len = 0; len<=j; len++)

umin(dp[i][j], dp[i-1][j-len] + mm[i][len]);
}
}

int minn = INF;
for(int i=0; i<=k; i++)
umin(minn, dp[n-1][i]);

printf("%d\n", minn);

}
};最后选择了一个for循环来取minn的值,是因为如果k比总课程大的话,dp[n-1][k] 所对应的为恰好翘k节课的时间会出问题。然后在预处理mm的时候使用了枚举连续区间[l,r]作为上课区间,而不是用头尾翘课的方式。当时脑子里有些懵所以用了特殊的变量名并打了注释。还是很好理清思路的。

这场cf出了三个简单题,栽了一道dp。可是简单题并没有保证手速和正确率,B C两题各WA了一发,如果是真的在打场的话应该就凉了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐