这次打cf第一次长分,比赛时做了A、B、C三道题,赛完了再做了D题。比赛开始两题很快就过了,一个7分钟一个30分钟,不过还是感觉英语着急,看题用了很长的时间。第三题就更蛋疼了,看了半个小时没看明白,代码也连交了两次WA,最后发现是修改代码的时候一个地方忘记删掉了,删了就直接A,不过也没时间了,第四题就没怎么看了。到后面测大数据的时候就坑了,第三题竟然Wrong answer on 34,看了下数据,确实贪心的思路有问题,不过在加个枚举就应该对了,改了一下AC。感觉有点遗憾,不过cf真心好玩,以后一定要坚持打,希望能分数越来越高
A. Helpful Maths
题目链接:http://codeforces.com/problemset/problem/339/A
题目大意:给一串加法式子,其中的数字只会是1、2、3,需要输出数字为升序的加法式子
解题思路:sort排序
#include<iostream>
#include<string>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 105
int main ()
{
string s;
while(cin >> s)
{
int num[N];
int len = s.size(), t = 0;
for(int i = 0; i < len ; i++)
{
if(s[i] >= '1' && s[i] <= '3')
num[t++] = s[i]-'0';
}
sort(num, num+t);
for(int i = 0; i < t-1; i++)
printf("%d+", num[i]);
printf("%d\n",num[t-1]);
}
return 0;
}
B. Xenia and Ringroad
题目链接:http://codeforces.com/contest/339/problem/B
题目大意:输入n, m (2 ≤ n ≤ 105, 1 ≤ m ≤ 105). n代表有n个房子,m代表要访问m个房子,注意规定只能按顺时针查找,输出要经过的路段长,每一个房子间的距离都为1,还需注意Xenia 可访问同一家房多次,样例2就是例子
解题思路:模拟
#include<stdio.h>
#define N 100005
int a[N];
int main ()
{
int n, m;
int i, j;
while(scanf("%d %d", &n, &m) != EOF)
{
__int64 ans = 0;
for(i = 1; i <= m; i++)
scanf("%d", &a[i]);
ans = a[1] - 1;
for(i = 2; i <= m; i++)
{
if(a[i] == a[i-1]) continue;
if(a[i] > a[i-1]) {ans += a[i]-a[i-1]; continue;}
if(a[i] < a[i-1]) {ans += (n-a[i-1]+1) + a[i]-1; continue;}
}
printf("%I64d\n", ans);
}
return 0;
}
C. Xenia and Weights
题目大意:有重量为1~10的砝码(数量无限多),你需要在天平上砝码,先放取一个砝码放左边,然后取一个砝码放右边,这样交替进行,并且规定每次前一个放的砝码不能和后一个放的砝码重量相同,且要保重这一次放砝码的一边的重量严格的大于另外一边。问能否按上述规定操作m次,若能,输出YES,并输出每一次放砝码的重量。若不能,输出NO.
解题思路:(有人用dp和搜索过了)当时比赛的时候用贪心的思路来写的,过了,不过被大数据砍了,跪在了Wrong answer on test34,一片贪心跪死人啊
test34数据:
Input
1110000000
4
Answer
YES
2 3 2 3
想一想确实,按贪心的思路肯定是从重量1开始放,输出的肯定是NO。不过如果枚举第一次放砝码的所以操作的话就可以过了,最多也就10个砝码,绝对不会超时~~~
#include<stdio.h>
int ans[1005];
int main ()
{
int s[15];
char num[15];
int i, j;
while(scanf("%s", num) != EOF)
{
int t = 0;
for( i = 0; i < 10; i++)
{
if(num[i] == '1')
s[t++] = i+1;
}
int n, cnt;
scanf("%d", &n);
for(int k = 0; k < t; k++)
{
cnt=1;
int l = 0, r = 0, flag = 0;
int lnum = -1, rnum = -1;
flag = 1;
l = s[k];
lnum = s[k];
ans[cnt++] = s[k];
for(j = 2; j <= n; j++)
{
if(!flag) //flag = 0, 放左边
{
flag = 1;
for( i = 0; i < t; i++)
{
if(s[i] == rnum) continue;
if(l+s[i] > r)
{
l += s[i];
lnum = s[i];
ans[cnt++] = s[i];
break;
}
}
if(i == t) break;
}
else
{
flag = 0;
for( i = 0; i < t; i++)
{
if(s[i] == lnum) continue;
if(r+s[i] > l)
{
r += s[i];
rnum = s[i];
ans[cnt++] = s[i];
break;
}
}
if(i == t) break;
}
}
if(j-1 == n) break;
}
if(j-1 == n)
{
printf("YES\n");
for(int i = 1; i < cnt-1; i++)
printf("%d ", ans[i]);
printf("%d\n", ans[cnt-1]);
}
else
printf("NO\n");
}
return 0;
}
D. Xenia and Bit Operations
题目链接:http://codeforces.com/problemset/problem/339/D
题目大意:有2^n个数,每两个数间先进行or操作合并为2^n-1个数,然后再每两个数之间进行xor操作合并为2^n-2个数,最后合并为一个数,问这一个数是什么?期间还有m个操作,每个操作输入p ,d两个数,代码将第p个数改为d。
解题思路:赤裸裸的线段树。
#include<stdio.h>
#define N (1<<18)+10
#define lson l,m,s<<1
#define rson m+1,r,s<<1|1
int tree[N<<2];
int n, m, temp_n;
void PushUp(int s, int count)
{
if((temp_n-count) % 2 != 0)//从底往上找是第几层,基数层进行or运算,偶数层进行xor运算
tree[s] = tree[s<<1] | tree[s<<1|1];
else
tree[s] = tree[s<<1] ^ tree[s<<1|1];
}
void updata(int p, int d, int l, int r, int s, int count)
{
if(l == r)
{
tree[s] = d;
return ;
}
int m = (l+r) >> 1;
if(m >= p)
updata(p,d,lson,count+1);
else
updata(p,d,rson,count+1);
PushUp(s, count);
}
int main ()
{
int i, j;
scanf("%d %d", &n, &m);
temp_n = n;
n = 1 << n;
for(i = 1; i <= n; i++)
{
int num;
scanf("%d", &num);
updata(i, num, 1, n, 1, 0);
}
for(i = 1; i <= m; i++)
{
int p, d;
scanf("%d %d", &p, &d);
updata(p, d, 1, n, 1, 0);
printf("%d\n", tree[1]);
}
return 0;
}
PS:线段树还很弱啊,一定要加油
E. Three Swaps
过几天再补上