比赛感想
上周周末因为补课的缘故没有参加比赛,今天集中了一下时间把比赛题重新做一下。
然后就发现,上周的比赛难度又上来了<苦笑>,提交榜也是惨不忍睹……
题目重现
Vasya and Golden Ticket
题意:
本题给你n个数字,让你将这n个数字按顺序进行划分,至少划分为两堆,如果有任意一种划分方法使得每一堆的数字之和加起来相等,则输出yes,否则输出no
感受:
这是一道我做不出来的题……我能想到的方法只有暴力解题,把所有的可能枚举出来然后计算每种可能,这么干指定是超时要是真有一百个数字还不知道要跑几十秒呢……
解题思路:
大佬的思路就是厉害!
官方的本题解法就是:以第一堆为标准,首先给第一堆划分一个数,然后对后面的数字依次进行分堆并对每一堆求和,当该堆之和大于等于第一堆的数字之和之后则本堆划分完毕,对后续的数字进行同样的操作,同时每一次完成一堆的划分都将其与第一堆进行比较,对结果进行存储。第一次循环进行结束之后就开始给第一堆划分两个数,操作和上述相同。
最后统一整理,就得出了本题答案。
//代码实现
#include <iostream>
#include <string>
using namespace std;
int n;
string s;
int main() {
//n是数字的个数,s是数字字符串
scanf("%d", &n);
cin >> s;
int sum = 0; //sum用来保存前i个数字的和
//第一层循环用来枚举前i位数字的和
for(int i = 0; i < n - 1; i++){
sum += s[i] - '0';
bool ok = true; //ok用来保存本题答案
int pos = i + 1; //pos主要用来记录第一堆之后的每个数字的下标,起指针的作用
int sum2 = 0; //sum2用来临时保存第二堆及以后每堆的和
//每一次循环结束都代表新划分出了一堆
while(pos < n){
sum2 = s[pos] - '0';
pos++;
//该循环是计算每一堆的数字之和
while(pos < n && sum2+s[pos]-'0' <= sum){
sum2 += s[pos] - '0';
pos++;
}
if(sum2 != sum) ok = false;
}
if(sum2 != sum) ok = false;
if(ok){
printf("YES");
return 0;
}
}
printf("NO");
return 0;
}
Curiosity Has No Limits
题意:现在给出两组数,第一组是a1, a2, a3, ……, an,第二组是b1, b2, b3, ……, bn。令a1 = c1|c2, b1 = c1&c2,问能不能找到这样符合条件的一组数c1, c2, c3, ……, cn, cn+1。
解题思路:
我的错误思路:
起初我的想法是,现在已经得到的是数组c相邻两个数的交运算和并运算的结果,用暴力匹配应该是可以做出来的,但是我自作聪明想用简单一点的方法试一试
想了好久我觉得既然不能从数组c推出数组a、b的正确性,那我应该试试通过数组a判断数组b是否有可能存在,然后我就列出了a的所有取值对应的c的可能数对以及在该取值下b的所有可能
首先得到的结论是b的每一个数都不可能大于a,然后首先设置一个限制条件,若b大于a,则不能得到数组c
然后寻找规律,我发现a, b的值正好是c1, c2的值的,再根据第一个条件就可以进一步通过a来筛选b的值(很明显最后问题出来了,我看漏了当a=3的时候取值问题),然后写到最后我就写不下去了……代码也拿出来参考参考吧,对了,样例通过了
//代码实现
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n, x;
scanf("%d", &n);
n--;
vector<int> a(n);
vector<int> b(n);
vector<int> c(n+1);
for(int i=0; i<n; i++){
scanf("%d", &x);
a[i] = x;
}
for(int i=0; i<n; i++){
scanf("%d", &x);
b[i] = x;
}
for(int i=0; i<n; i++){
if(a[i] < b[i]){
printf("NO");
return 0;
}
}
if(a[0]==a[1] || a[0]==b[1]){
x = a[0];
a[0] = b[0];
b[0] = x;
}
c[0] = a[0];
c[1] = b[0];
for(int i=1; i<n; i++){
if(b[i] == a[i+1]){
c[i+1] = b[i];
}else if(b[i] == b[i+1]){
x = a[i+1];
a[i+1] = b[i+1];
b[i+1] = x;
c[i+1] = b[i];
// }else if(a[i]==3 && b[i]==0)){
// if()
// }
else{
printf("NO");
return 0;
}
}
printf("YES\n");
for(int i=0; i<n+1; i++){
printf("%d ", c[i]);
}
return 0;
}
最后还是意识到我的歪门邪道还是跟官方题解搭不上边,于是乎我就参考了官方题解……
总之吧,因为数据不大,还是使用了枚举匹配,好像也挺方便的,代码也放下边了
#include<iostream>
using namespace std;
int main(){
int n,i,j;
scanf("%d", &n);
int a[n+1],b[n+1],t[n+100];
for(i=0;i<n-1;i++) cin>>a[i];
for(i=0;i<n-1;i++) cin>>b[i];
for(i=0;i<4;i++){
t[0]=i;
for(j=1;j<n;j++){
t[j]=a[j-1]+b[j-1]-t[j-1];
if(((t[j]|t[j-1])!=a[j-1])||((t[j]&t[j-1])!=b[j-1])) break;
}
if(j==n) break;
}
if(i==4){
printf("NO");
}else{
printf("YES\n");
for(i=0;i<n;i++)cout<<t[i]<<" ";
}
}