官方题解
http://codeforces.com/blog/entry/13181
Problem A:
After winning gold and silver in IOI 2014, Akshat and Malvika want to have some fun. Now they are playing a game on a grid made of nhorizontal and m vertical sticks.
An intersection point is any point on the grid which is formed by the intersection of one horizontal stick and one vertical stick.
In the grid shown below, n = 3 and m = 3. There are n + m = 6 sticks in total (horizontal sticks are shown in red and vertical sticks are shown in green). There are n·m = 9 intersection points, numbered from 1 to 9.
![](http://espresso.codeforces.com/91558f9cc7c96dff04bc29434dac2798ddbcf518.png)
The rules of the game are very simple. The players move in turns. Akshat won gold, so he makes the first move. During his/her move, a player must choose any remaining intersection point and remove from the grid all sticks which pass through this point. A player will lose the game if he/she cannot make a move (i.e. there are no intersection points remaining on the grid at his/her move).
Assume that both players play optimally. Who will win the game?
The first line of input contains two space-separated integers, n and m (1 ≤ n, m ≤ 100).
Print a single line containing "Akshat" or "Malvika" (without the quotes), depending on the winner of the game.
2 2
Malvika
2 3
Malvika
3 3
Akshat
Explanation of the first sample:
The grid has four intersection points, numbered from 1 to 4.
![](http://espresso.codeforces.com/91877e206bb6f5266de63fa72a87c2de47f00e83.png)
If Akshat chooses intersection point 1, then he will remove two sticks (1 - 2 and 1 - 3). The resulting grid will look like this.
![](http://espresso.codeforces.com/fb4a3537dc75368670f749402f956a788cf0d39a.png)
Now there is only one remaining intersection point (i.e. 4). Malvika must choose it and remove both remaining sticks. After her move the grid will be empty.
In the empty grid, Akshat cannot make any move, hence he will lose.
Since all 4 intersection points of the grid are equivalent, Akshat will lose no matter which one he picks.
注意到每次取走一个交叉点的同时水平和数值的线就会减少一个,当某一个方向的线为0的时候就不存在交叉点了。因此只需要判断一下较小的那个值的奇偶性即可。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
/*
CF_round258_A
by :dezhonger
*/
int main()
{
int t, m, n;
while( cin >> m >> n)
{
t = n;
if(m < n) t = m;
if(t % 2 == 0) cout << "Malvika" << endl;
else cout << "Akshat" << endl;
}
return 0;
}
Problem B:
Being a programmer, you like arrays a lot. For your birthday, your friends have given you an array a consisting of n distinct integers.
Unfortunately, the size of a is too small. You want a bigger array! Your friends agree to give you a bigger array, but only if you are able to answer the following question correctly: is it possible to sort the array a (in increasing order) by reversing exactly one segment of a? See definitions of segment and reversing in the notes.
The first line of the input contains an integer n (1 ≤ n ≤ 105) — the size of array a.
The second line contains n distinct space-separated integers: a[1], a[2], ..., a[n] (1 ≤ a[i] ≤ 109).
Print "yes" or "no" (without quotes), depending on the answer.
If your answer is "yes", then also print two space-separated integers denoting start and end (start must not be greater than end) indices of the segment to be reversed. If there are multiple ways of selecting these indices, print any of them.
3 3 2 1
yes 1 3
4 2 1 3 4
yes 1 2
4 3 1 2 4
no
2 1 2
yes 1 1
Sample 1. You can reverse the entire array to get [1, 2, 3], which is sorted.
Sample 3. No segment can be reversed such that the array will be sorted.
Definitions
A segment [l, r] of array a is the sequence a[l], a[l + 1], ..., a[r].
If you have an array a of size n and you reverse its segment [l, r], the array will become:
a[1], a[2], ..., a[l - 2], a[l - 1], a[r], a[r - 1], ..., a[l + 1], a[l], a[r + 1], a[r + 2], ..., a[n - 1], a[n].
题目意思是给定一个数组,每个数均不相同。给定一个操作,这个操作是翻转原数组中的一段,问操作之后可不可以使得原数组变得递增。
我的解法是,找到第一个 a[i+1] < a[i]的索引,因为这里开始肯定要翻转,再找到结束翻转的位置,即 a[i+1] > a[i],因为这里满足了,不需要翻转了。 然后判断一下中间翻转后是否满足第一个数比它之前那个数大,最后一个数比之后那个数小。
之后如果数组是升序的,就yes,如果还存在降序的部分,那就no了。
代码写的比较乱。
#include <iostream>
using namespace std;
#define maxn 100000 + 10
int a[maxn];
int main()
{
int n, i, f, index, f1;
while( cin >> n)
{
f = 1;
f1 = 1;
for(i = 1; i <= n; i++ )
{
cin >> a[i];
}
a[0] = 0;
a[n + 1] = 1000000000 + 100;
for(i = 1; i <= n; i++ )
{
if( a[i + 1] < a[i] )
{
if(f == 1)
{
index = i;//
f = 0;
}
}
else if(f == 0)
{
if(( index > 1 && a[i] < a[index - 1 ] )|| ( i < n && a[index] > a[i + 1]))
{
f1 = 0;//
break;
}
else break;
}
}
if(f1 == 0) { cout << "no" << endl; continue;}
int k = i;
for(i = i + 1; i < n; i++)
{
if(a[i+1] < a[i]) {f1 = 0; break;}
}
if(f) cout << "yes" << endl << "1 1" << endl;
else if(f1 == 0) cout << "no" << endl;
else if(f == 0 && f1 == 1) cout << "yes" << endl << index << " " << k << endl;
else ;
}
return 0;
}
Problem C:
There are n games in a football tournament. Three teams are participating in it. Currently k games had already been played.
You are an avid football fan, but recently you missed the whole k games. Fortunately, you remember a guess of your friend for these kgames. Your friend did not tell exact number of wins of each team, instead he thought that absolute difference between number of wins of first and second team will be d1 and that of between second and third team will be d2.
You don't want any of team win the tournament, that is each team should have the same number of wins after n games. That's why you want to know: does there exist a valid tournament satisfying the friend's guess such that no team will win this tournament?
Note that outcome of a match can not be a draw, it has to be either win or loss.
The first line of the input contains a single integer corresponding to number of test cases t (1 ≤ t ≤ 105).
Each of the next t lines will contain four space-separated integers n, k, d1, d2 (1 ≤ n ≤ 1012; 0 ≤ k ≤ n; 0 ≤ d1, d2 ≤ k) — data for the current test case.
For each test case, output a single line containing either "yes" if it is possible to have no winner of tournament, or "no" otherwise (without quotes).
5 3 0 0 0 3 3 0 0 6 4 1 0 6 3 3 0 3 3 3 2
yes yes yes no no
Sample 1. There has not been any match up to now (k = 0, d1 = 0, d2 = 0). If there will be three matches (1-2, 2-3, 3-1) and each team wins once, then at the end each team will have 1 win.
Sample 2. You missed all the games (k = 3). As d1 = 0 and d2 = 0, and there is a way to play three games with no winner of tournament (described in the previous sample), the answer is "yes".
Sample 3. You missed 4 matches, and d1 = 1, d2 = 0. These four matches can be: 1-2 (win 2), 1-3 (win 3), 1-2 (win 1), 1-3 (win 1). Currently the first team has 2 wins, the second team has 1 win, the third team has 1 win. Two remaining matches can be: 1-2 (win 2), 1-3 (win 3). In the end all the teams have equal number of wins (2 wins).
题目大意:有n场比赛,已经比赛过了k场,其中三只队伍胜场分别为 h1, h2 , h3,题目中给定了 d1 = abs(h1 - h2), d2 = abs(h2 - h3), 问比完接下来的 n - k场比赛之后,能否使三个队伍的胜场相同。
解析:
分析所有的情况
x, x + d1, x + d2
x, x - d1, x - d2
x + d1, x , x + d2
x - d1, x , x - d2
如果任意一种情况有解就yes。否则no。
我们以第一种为例解析一下。
x = k - (2 * d1 + d2);
x必须是3的倍数,然后解出h1, h2 ,h3显然三个都必须>= 0,然后他们与 n / 3的差也必须>=0.(显然,n必须是3的倍数)
即为long long a = n / 3;
long long h1, h2, h3;
h1 = x, h2 = x + d1; h3 = x + d1 + d2;
long long t1 = a - h1, t2 = a - h2, t3 = a - h3;
if(x >= 0 && n % 3 == 0 && t1 >= 0 && t2 >= 0 && t3 >= 0 && h1 >= 0 && h2 >= 0 && h3 >= 0) return true;
return false;
#include <iostream>
#include <algorithm>
using namespace std;
long long n, k, d1, d2;
bool judge1() // x , x + d1, x + d1 + d2
{
long long sum = 2 * d1 + d2;
long long x = k - sum;
if(x % 3 != 0) return false;
x /= 3;
long long a = n / 3;
long long h1, h2, h3;
h1 = x, h2 = x + d1; h3 = x + d1 + d2;
long long t1 = a - h1, t2 = a - h2, t3 = a - h3;
if(x >= 0 && n % 3 == 0 && t1 >= 0 && t2 >= 0 && t3 >= 0 && h1 >= 0 && h2 >= 0 && h3 >= 0) return true;
return false;
}
bool judge2() // x , x - d1, x - d1 - d2
{
long long sum = 2 * d1 + d2;
long long x = k + sum;
if(x % 3 != 0) return false;
x /= 3;
long long a = n / 3;
long long h1, h2, h3;
h1 = x, h2 = x - d1; h3 = x - d1 - d2;
long long t1 = a - h1, t2 = a - h2, t3 = a - h3;
if(x >= 0 && n % 3 == 0 && t1 >= 0 && t2 >= 0 && t3 >= 0 && h1 >= 0 && h2 >= 0 && h3 >= 0) return true;
return false;
}
bool judge3() //x - d1, x, x - d2
{
// long long sum = 2 * d1 + d2;
long long x = k + d1 + d2;
if(x % 3 != 0) return false;
x /= 3;
long long a = n / 3;
long long h1, h2, h3;
h1 = x - d1, h2 = x ; h3 = x - d2;
long long t1 = a - h1, t2 = a - h2, t3 = a - h3;
if(x >= 0 && n % 3 == 0 && t1 >= 0 && t2 >= 0 && t3 >= 0 && h1 >= 0 && h2 >= 0 && h3 >= 0) return true;
return false;
}
bool judge4() //x + d1, x, x + d2
{
// long long sum = 2 * d1 + d2;
long long x = k - d1 - d2;
if(x % 3 != 0) return false;
x /= 3;
long long a = n / 3;
long long h1, h2, h3;
h1 = x + d1, h2 = x ; h3 = x + d2;
long long t1 = a - h1, t2 = a - h2, t3 = a - h3;
if(x >= 0 && n % 3 == 0 && t1 >= 0 && t2 >= 0 && t3 >= 0 && h1 >= 0 && h2 >= 0 && h3 >= 0) return true;
return false;
}
int main()
{
int t;
cin >> t;
while( t-- )
{
cin >> n >> k >> d1 >> d2;
if( judge1() || judge2() || judge3() || judge4() )
cout << "yes" << endl;
else
cout << "no" << endl;
/*
if(judge1()) cout << "1" << endl;
if(judge2()) cout << "2" << endl;
if(judge3()) cout << "3" << endl;
if(judge4()) cout << "4" << endl;*/
}
return 0;
}
Problem D:
We call a string good, if after merging all the consecutive equal characters, the resulting string is palindrome. For example, "aabba" is good, because after the merging step it will become "aba".
Given a string, you have to find two values:
- the number of good substrings of even length;
- the number of good substrings of odd length.
The first line of the input contains a single string of length n (1 ≤ n ≤ 105). Each character of the string will be either 'a' or 'b'.
Print two space-separated integers: the number of good substrings of even length and the number of good substrings of odd length.
bb
1 2
baab
2 4
babb
2 5
babaa
2 7
In example 1, there are three good substrings ("b", "b", and "bb"). One of them has even length and two of them have odd length.
In example 2, there are six good substrings (i.e. "b", "a", "a", "b", "aa", "baab"). Two of them have even length and four of them have odd length.
In example 3, there are seven good substrings (i.e. "b", "a", "b", "b", "bb", "bab", "babb"). Two of them have even length and five of them have odd length.
Definitions
A substring s[l, r] (1 ≤ l ≤ r ≤ n) of string s = s1s2... sn is string slsl + 1... sr.
A string s = s1s2... sn is a palindrome if it is equal to string snsn - 1... s1.
题意:给一个字串,定义一个字串是good的,当且他们归并字串相同的字符之后是回文的,输出字串是good的长度为偶数和奇数的个数。
只要注意到,一个字串是good的,只要他的第一个字符和最后一个字符是相同的就可以了。
我们只要扫一遍,并且统计下标分别是偶数和奇数的a的个数以及b的个数,就可以了。
时间复杂度为O(n)
//注意开 long long
#include <iostream>
using namespace std;
/*
CF_round258_D
dezhonger
*/
//注意到只要一个字串的第一个和最后一个字符相等,这个字串即为“good”的.
char s[100000 + 10];
long long a[2], b[2];
//字符a在奇数位置a[0]个
//字符a在偶数位置a[1]个
//字符b在奇数位置b[0]个
//字符b在偶数位置b[1]个
long long anseven;//偶数答案
long long ansodd;//奇数答案
void solve()
{
a[0] = a[1] = b[0] = b[1] = 0;
anseven = ansodd = 0;
for(int i = 0; s[i] != '\0'; i++ )
{
if( s[i] == 'a' && i % 2 == 1) a[0]++;
else if( s[i] == 'a' && i % 2 == 0) a[1]++;
else if( s[i] == 'b' && i % 2 == 1) b[0]++;
else b[1]++;
if(s[i] == 'a' && i % 2 == 1) ansodd += a[0], anseven += a[1];
if(s[i] == 'a' && i % 2 == 0) ansodd += a[1], anseven += a[0];
if(s[i] == 'b' && i % 2 == 1) ansodd += b[0], anseven += b[1];
if(s[i] == 'b' && i % 2 == 0) ansodd += b[1], anseven += b[0];
}
}
int main()
{
while( cin >> s )
{
solve();
cout << anseven << " " << ansodd << endl;
}
return 0;
}
Problem E:
Devu wants to decorate his garden with flowers. He has purchased n boxes, where the i-th box contains fi flowers. All flowers in a single box are of the same color (hence they are indistinguishable). Also, no two boxes have flowers of the same color.
Now Devu wants to select exactly s flowers from the boxes to decorate his garden. Devu would like to know, in how many different ways can he select the flowers from each box? Since this number may be very large, he asks you to find the number modulo (109 + 7).
Devu considers two ways different if there is at least one box from which different number of flowers are selected in these two ways.
The first line of input contains two space-separated integers n and s (1 ≤ n ≤ 20, 0 ≤ s ≤ 1014).
The second line contains n space-separated integers f1, f2, ... fn (0 ≤ fi ≤ 1012).
Output a single integer — the number of ways in which Devu can select the flowers modulo (109 + 7).
2 3 1 3
2
2 4 2 2
1
3 5 1 3 2
3
Sample 1. There are two ways of selecting 3 flowers: {1, 2} and {0, 3}.
Sample 2. There is only one way of selecting 4 flowers: {2, 2}.
Sample 3. There are three ways of selecting 5 flowers: {1, 2, 2}, {0, 3, 2}, and {1, 3, 1}.
题意:给了n, s (1 ≤ n ≤ 20, 0 ≤ s ≤ 1014). n种花朵,每种有f[i]个,(0 ≤ fi ≤ 1012).求组成s的不同方法数。答案模1E10 + 7.
题解:
先写为Generate Function的形式(1 + x + x2 + x3 + + ..xf1) * * * (1 + x + x2 + x3 + + ..xfn).
变形,使用 (1 + x + x2 + x3 + + ..xf1) = (1 - x(f1 + 1)) / (1 - x).,我们可以得到
(1 - x(f1 + 1)) / (1 - x) * * * (1 - x(fn + 1)) / (1 - x).
= (1 - x(f1 + 1)) * .. * (1 - x(fn + 1)) * (1 - x)( - n).
Now we can find xs in (1 - x) - n easily. It is![](http://espresso.codeforces.com/80d2d6201f529353bf07339a9eff960544560e51.png)
然后把(1 - x(f1 + 1)) * .. * (1 - x(fn + 1)) *展开。N最大20.
#include <iostream>
#include <cmath>
//CF上cxlove的代码,稍作修改。
using namespace std;
typedef long long LL;
const int N = 100005;
const LL MOD = 1000000007LL;
int n;
LL s , f[N];
//invert, x的逆 mod p
LL inv (LL x)
{
return x == 1 ? 1 : (MOD - MOD / x) * inv (MOD % x) % MOD;
}
/*
C(n, m) = n! / (m! * (n - m)! ) = n! / (n - m)! /m! = n * (n - 1) * ... (n - m + 1) /m! =
=n * (n - 1) * ... (n - m + 1) /1/2/3/4/.../m;
除以x的阶乘mod p 等价于乘以x的逆modp
*/
LL binom (LL n , LL m)
{ //求二项式系数C(n, m)
if (n < 0 || m < 0 || m > n)
return 0 ;
LL ret = 1;
for (LL i = n ; i > n - m ; i --)
ret = ret * (i % MOD) % MOD;
for (LL i = 0 ; i < m ; i ++)
ret = ret * inv (i + 1) % MOD; //除以m!的阶乘mod p 等价于乘以m!的逆mod p, invert()函数求解mod p下i的逆
return ret;
}
int main(){
cin >> n >> s;
for (int i = 0 ; i < n ; i ++)
cin >> f[i];
LL ans = 0;
//二进制枚举每个括号里的情况,1表示选了x^(f[i]+1)这一项,注意到这一项是的系数为-1,所以在选取了奇数项的时候,应该从答案中减去。
for (int i = 0 ; i < 1 << n ; i ++) {
int cnt = 0;LL p = 0;
for (int j = 0 ; j < n ; j ++)
if (i & (1 << j))
cnt ++ , p += f[j] + 1;
if (cnt & 1) ans -= binom (s - p + n - 1 , n - 1); // 1/(1-x)^n, x ^ k的系数为 C(n + k - 1, k) == C(n + k - 1, n - 1);
else ans += binom (s - p + n - 1 , n - 1);
ans = (ans % MOD + MOD) % MOD;
}
cout << ans << endl;
return 0;
}