开始听说这场比赛还比较难,但是做了以后感觉其实并不难,只不过是自己太菜了~基本上都是用不到什么算法的题目
前面两道水题还卡了一会,还是室友找到了错误。总结了一下就是能不优化就不优化,没必要的优化就可能会错。无脑暴力就好了。
1001题 传递
先说A题,这道题如果推的话应该是很难的但是有一个比较投机的做法就是随机1e7的数据(这个很容易),然后就过了。随机的次数要多,并且还得看运气....换了个种子可能就会过不了。不过也是学到了一个做法。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
char str[2020][2020];
int main() {
int t;
scanf("%d",&t);
while(t--) {
int n;
scanf("%d",&n);
for(int i = 0;i < n;i++)
scanf("%s",str[i]);
int cnt = 0,flag = 1;
//srand(time(0)); //加上这句就过不了,orz
while(cnt < 10000000) { //随机一千万组数据
int a = rand()%n;
int b = rand()%n;
int c = rand()%n; //%n确保数据范围在0到n
cnt++;
if(str[a][b] == 'Q' && str[b][c] == 'Q' && str[a][c] != 'Q') {
flag = 0;
break;
}
if(str[a][b] == 'P' && str[b][c] == 'P' && str[a][c] != 'P') {
flag = 0;
break;
}
}
if(flag) printf("T\n");
else printf("N\n");
}
}
1003题 朋友
这道题算是博弈论中的一个题型,但是没学过的人也该有可以做。
要找到一个规律,如果只考虑一条路,那么根的最近的边是1,先选的人必胜,否则先选的人必败。
那么我们只要考虑和当前根结点相连接的边的权值的和,mod 1 后如果为1就是先选的人(girl)胜,否则后选的人(boy)胜。
还有要考虑的就是更新边权,要注意如果边(a,b)本来权值就是1,题目要求(1,a,b,1),那么相当于不更新,这样的话就需要一个map来存边权的信息,再更新即可。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
int va[40005];
typedef pair<int,int> pii;
map<pii,int> edge;
int main() {
int t;
scanf("%d",&t);
while(t--) {
int n,m;
scanf("%d%d",&n,&m);
memset(va,0,sizeof(va));
for(int i = 1;i < n;i++) {
int x,y,v;
scanf("%d%d%d",&x,&y,&v);
if(x > y) swap(x,y); //将x,y的值排序,就不用再记录edge[pii(y,x)]了
edge[pii(x,y)] = v;
if(v) {
va[x]++;va[y]++;
}
}
for(int i = 1;i <= m;i++) {
int q,x,y,z;
scanf("%d",&q);
if(q) {
scanf("%d%d%d",&x,&y,&z); //更新边权的信息
if(x > y) swap(x,y);
if(z && !edge[pii(x,y)]) {
va[x]++;va[y]++;
edge[pii(x,y)] = 1;
}
else if(!z && edge[pii(x,y)]) {
va[x]--;va[y]--;
edge[pii(x,y)] = 0;
}
}
else {
scanf("%d",&x);
if(va[x] % 2 == 0) printf("Boys win!\n");
else printf("Girls win!\n");
}
}
}
}
1005题 扫雷
这题就是一个简单的递推或者dp,千万不能把它想的太难,就是总结规律,找到联系。
因为有三行N列,中间的已经知道是数字,上下两行放地雷。那么对于每一列,我们只要考虑四种情况。
1、第一行和第三行都不放 总数是0个
2、第一行放,第三行不放 总数是1个
3、第一行不放,第三行放 总数是1个
4、第一行和第三行都放 总数是2个
这样的话,对于每一列,就是放0个地雷和2个地雷都是一种情况,放1个的时候有两种。
我们就可以先对第一列的所有情况遍历,然后后面怎么放就可以由第一列的情况推出来,不符合条件的就跳过,最后得出结果。
具体看代码:
#include<bits/stdc++.h>
using namespace std;
const long long mod = 1e8+7;
char str[10005];
int num[10005],a[10005];
int main() {
//freopen("out.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--) {
scanf("%s",str);
int n = strlen(str);
for(int i = 0;i < n;i++)
num[i] = str[i] - '0';
int dd,flag;
long long ans = 0;
if(n == 1) { //单独考虑长度为1的时候
if(num[0] == 0 || num[0] == 2) printf("1\n");
else if(num[0] == 1) printf("2\n");
else printf("0\n");
continue;
}
if(num[0] > 4) {printf("0\n"); continue;}
for(int i = 0;i <= num[0] && i <= 2;i++) { //遍历第一列由多少情况
a[1] = num[0] - i;
a[0] = i;flag = 1;
for(int j = 1;j <= n-1;j++) {
a[j+1] = num[j] - (a[j-1]+a[j]);
if(a[j+1] < 0 || a[j+1] > num[j+1] || a[j+1] > 2) {
flag = 0;
break;
}
}
if(a[1] > 2 || a[1] < 0) continue;
if(num[n-1] != a[n-1]+a[n-2]) flag = 0;
if(!flag) {
continue;
}
dd = 1;
for(int i = 0;i < n;i++) {
if(a[i]+a[i-1]+a[i+1] != num[i]) continue;
if(a[i] == 1) //放1的时候方案数*2并且取余
dd = (dd*2)%mod;
}
ans = (dd+ans) % mod;
}
printf("%I64d\n",ans % mod);
}
}
总结了还是要多练,还有就是脑洞要打开,不要把题目想的太难了,总结了规律,铜牌的题还是很好做的。
继续加油吧!