题目链接:http://codeforces.com/contest/1194
Problem A
找规律,发现会一次去掉1,3,5,7直到剩余数字小于等于一半
于是奇数剩余:2,4,6,...n-1
偶数剩余:2,4,6,....n
问你第几个数,只要*2就行了
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define pb push_back
#define fi first
#define se second
#define debug(x) printf("----Line %s----\n",#x)
#define pt(x,y) printf("%s = %d\n",#x,y)
#define INF 0x3f3f3f3f
const int N = 1e5+5;
int main()
{
int T;scanf("%d",&T);while (T--){
ll n,x;
scanf("%I64d %I64d",&n,&x);
printf("%I64d\n",x*2);
}
return 0;
}
Problem B
送命题,复杂度摸不透,比赛时候觉得暴力的话空间开不起,时间不够跑。
一行行遍历时用vector储存下所有最长的行上面的空白格的位置(因为可能不止一条最长的),这写空白的位置是为了等会选取
最长竖时是否存在可以共同填掉一格,当然也要记下‘*’最多的那一(几)行的‘*’数目
遍历的时候同时统计每一列的‘*’数目cnt[]。
当遍历完整个图的时候,我们把vector里面的空白格全部倒出来开一个bool数组标记每个空白格的位置
开始遍历cnt也就是每一列的‘*’数目,来求答案,如果当前列的空白格被标记过,说明如果我们要填充这一列,这个空白格可以
同时受用这一列和最长的一行,所以总共需要涂色的等于最大行和这一列所欠缺的。取最大值即可。。。。。。
等等,为什么这种复杂度都能过啊喂???!
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define pb push_back
#define fi first
#define se second
#define debug(x) printf("----Line %s----\n",#x)
#define pt(x,y) printf("%s = %d\n",#x,y)
#define INF 0x3f3f3f3f
const int N = 5e4+5;
vector<int>br;
int cnt[N];
bool kong[N];
int main()
{
int T;scanf("%d",&T);while (T--){
br.clear();
memset(cnt,0,sizeof cnt);
int n,m;
int sum=-1,maxlen=-1,maxrow=-1;
char c;
scanf("%d %d",&n,&m);
getchar();
for1(i,1,n){
sum = 0;
vector<int>temp;
for1(j,1,m){
scanf("%c",&c);
if (c=='.') temp.pb(j);
else cnt[j]++,sum++;
}
getchar();
if (sum>maxlen) br.clear(),br=temp,maxlen = sum;
else if (sum==maxlen) br.insert(br.end(),temp.begin(),temp.end());
}
//for (auto now:br) cout << now << " "; puts("");
memset(kong,false,sizeof kong);
for (auto now:br) kong[now] = true;
//for1(i,1,m)printf("%s",kong[i]?"kong ":"man ");puts("");
int ans = n+m+1;
for1(i,1,m){
if (cnt[i]>=maxrow){
if (kong[i]) ans = min(ans,n-cnt[i]+(m-maxlen)-1);
else ans = min(ans,n-cnt[i]+(m-maxlen));
maxrow = cnt[i];
}
}
printf("%d\n",ans);
}
return 0;
}
Problem C
把第三个串拥有的字符统计出来相当于第一个串的后备隐藏能源,来和第二个串匹配,优先用串1自己的匹配串2,
最后成功的条件是串1用完,串2用完,否则不成功。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define pb push_back
#define fi first
#define se second
#define debug(x) printf("----Line %s----\n",#x)
#define pt(x,y) printf("%s = %d\n",#x,y)
#define INF 0x3f3f3f3f
#define idx(i) i-96
const int N = 1e5+5;
char s[110],t[110],p[110];
int cnt[30];
int main()
{
int T;scanf("%d",&T);while (T--){
scanf("%s %s %s",s,t,p);
memset(cnt,0,sizeof cnt);
for (int i=0;p[i];i++)
cnt[idx(p[i])]++;
int tot=0,i=0;
int lens = strlen(s);
int lent = strlen(t);
for (i=0;i<lent;i++){
if (t[i]==s[tot]) tot++;
else if (cnt[idx(t[i])]>0) cnt[idx(t[i])]--;
else break;
}
if (tot==lens && i>=lent) printf("Yes\n");
else puts("No");
}
return 0;
}
Problem D
问题转换为:n个石头,每次可取1,2,k个,先取完就赢。
这道题只有一堆,跟sg函数看起来扯不到关系。
询问有很多次,每次k都不同,那么应该有什么共同的规律。
打个表找找规律。
k不是3的倍数时:
B AAB AAB AAB...
是三3倍数时:
k=3,B AAAB AAAB AAAB...
k=6,B AAB AAAB AAB AAAB ...
k=9,B AAB AAB AAAB AAB AAB AAAB...
k=12,B AAB AAB AAB AAAB AAB AAB AAB AAAB...
......
打表:(不是AC代码,那个在下面)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define pb push_back
#define fi first
#define se second
#define debug(x) printf("----Line %s----\n",#x)
#define pt(x,y) printf("%s = %d\n",#x,y)
#define INF 0x3f3f3f3f
const int N = 1e5+5;
char zt[N];
int main()
{
//freopen("C:/Users/DELL/Desktop/input.txt", "r", stdin);
//freopen("C:/Users/DELL/Desktop/output.txt", "w", stdout);
int n,k;
//int T;scanf("%d",&T);while (T--){}
while (~scanf("%d %d",&n,&k)){/// P 表示先手必胜,N 表示先手必败
zt[0] = 'N';
zt[1] = 'P';
zt[2] = 'P';
zt[k] = 'P';
for (int i=3;i<=n;i++)
if (zt[i-1]=='N'||zt[i-2]=='N'||(i>=k && zt[i-k]=='N')) zt[i] = 'P';
else zt[i] = 'N';
printf("当k=%d时:\n",k);
for0(i,0,n+1) printf("n = %d, %s\n",i,zt[i]=='P'?"Alice,first win":"Bob,second win");
}
return 0;
}
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define ll long long
#define for1(i,a,b) for (int i=a;i<=b;i++)
#define for0(i,a,b) for (int i=a;i<b;i++)
#define pb push_back
#define fi first
#define se second
#define debug(x) printf("----Line %s----\n",#x)
#define pt(x,y) printf("%s = %d\n",#x,y)
#define INF 0x3f3f3f3f
const int N = 1e5+5;
int a[N];
int main()
{
int T;scanf("%d",&T);
while (T--){
int n,k;
scanf("%d %d",&n,&k);
if (n==0){printf("Bob\n");continue;}
if (n==1||n==2){printf("Alice\n");continue;}
if (k%3!=0){
n = n%3;
if (n==1||n==2) printf("Alice\n");
else printf("Bob\n");
}
else {
int x = k/3-1;
int cycle = 3*x + 4;
n = n%cycle;
if (n==cycle-3||n==cycle-2||n==cycle-1) printf("Alice\n");
else if (n==0) printf("Bob\n");
else if (n%3==1||n%3==2) printf("Alice\n");
else printf("Bob\n");
}
}
return 0;
}
总结:
①AC了几千个人的题目一定没那么难,一定要想清楚,敢暴力
ps:vector可以直接容器间赋值,vector(v.begin,vv.begin,vv.end)可以直接实现对应位置的插入
②博弈论该去系统学一学了,sg,打表,各种变形。
③分已经真的没有掉的余地了,下一场让我多A几道,求你了