文章目录
A. Remove a Progression(思维)
原题链接:http://codeforces.com/contest/1194/problem/A
题意: 给你一个数 n,有 1 到 n 的数列,从1开始,每次去掉一个数。首先,去掉第一个,然后从剩下的数中去掉第二个数……,不断去掉,剩下的数必须不少于x,即在剩下的数列中要找的第 x 个数。问第 x 个数是什么。
思路: 可以看出去掉的其实就是原来序列数中的1,3,5…等奇数。那么,我们要求的是剩下数列的第 x 个数,显然就是 2*x。
Code(C++):
#include <iostream>
using namespace std;
int main() {
int t; cin>>t;
while(t--){
int n,x;
cin>>n>>x;
cout<<2*x<<endl;
}
return 0;
}
B. Yet Another Crosses Problem(思维)
原题链接:http://codeforces.com/contest/1194/problem/B
题意: 给一张 n * m 的字符地图,问是否存在某个点的行和列所有的单元格均是黑色的,若存在,则输出0,否则输出最少需要涂黑几个单元格才可以实现。
思路: 先记录每行每列所有单元格白色的个数,找出某个点所在行列最少的单元格数,若该点是白色,记得减掉重复的一个白色格子。即输出缺少黑色最少的行列所缺的个数。
注意字符二维数组最好用字符串数组来定义,下标要从0开始
Code(C++):
#include <iostream>
#include <cstring>
#define inf 0x3f3f3f3f
using namespace std;
const int N=5e4+100;
string a[N];
int h[N],l[N];
int main(){
int t; cin>>t;
while(t--){
memset(h,0,sizeof(h));
memset(l,0,sizeof(l));
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++) //字符串数组下标要从0开始
if(a[i][j]=='.')
h[i]++;
for(int j=0;j<m;j++)
for(int i=0;i<n;i++)
if(a[i][j]=='.')
l[j]++;
int k,minn=inf;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(a[i][j]=='.') //若是白格,要减掉重复的一个
k=-1;
else //若是黑格,则不需要
k=0;
minn=min(h[i]+l[j]+k,minn);
}
}
cout<<minn<<endl;
}
return 0;
}
C. From S To T(思维)
原题链接: http://codeforces.com/contest/1194/problem/C
题意: 三个字符串 s,t,p,问能否将 p 中的字符取出放入 s 中,使 s 成为 t 。
思路:
做法一: 可以运用STL容器中的 map来做,先把 p 字符串的字符存入map容器并计算其个数。然后在 t 字符串中查找 s 字符串相应位置,如果没有相同字符,则在map容器中查看是否有相应字符,若有,则该字符数量减1并将其插入 s 字符串相应位置,若没有,则直接跳出。最后比较操作后的 s 字符串是否与 t 字符串相同,若是,则输出 YES ,否则输出 NO。
做法二: 只需要判断是否满足两个条件:
- s 字符串和 p 字符串的所有相应字符数量是否大于等于 t 字符串相应字符数量,如果不够则直接跳出。
- 判断s 字符串是否为 p 字符串子序列,即 s 字符串有的字符是否在 t 字符串中均有。
Code1(C++):
#include <iostream>
#include <map>
using namespace std;
int main(){
int k; cin>>k;
while(k--){
string s,t,p;
cin>>s>>t>>p;
map<char,int> m;
for(int i=0;i<p.size();i++)
m[p[i]]++;
for(int i=0;i<=t.size();i++){
if(s[i]!=t[i]){
if(m[t[i]]>0){
m[t[i]]--;
s.insert(i,1,t[i]);
}else
break;
}
}
if(s==t)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
Code2(C++):
#include <iostream>
using namespace std;
int main(){
int q; cin>>q;
while(q--){
string s,t,p;
cin>>s>>t>>p;
int lens=s.size();
int lent=t.size();
int lenp=p.size();
int n1[26]={0},n2[26]={0};
for(int i=0;i<lens;i++) n1[s[i]-'a']++;
for(int i=0;i<lenp;i++) n1[p[i]-'a']++;
for(int i=0;i<lent;i++) n2[t[i]-'a']++;
int vis=1;
for(int i=0;i<26;i++){
if(n1[i]<n2[i])
vis=0;
}
int i,j;
for(i=0,j=0;i<lent;i++){
if(s[j]==t[i])
j++;
}
if(j!=lens)
vis=0;
if(vis)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
D. 1-2-K Game(博弈+SG函数+规律)
原题链接: http://codeforces.com/contest/1194/problem/D
题意: 当前在 n 位置,每一次可以向左走1,2,或者 k 步,最左的位置是0,不能走到0的左边, 二人博弈问题,谁没法再走的时候就输掉,问先手必赢还是后手必赢。
思路: 首先确定的是 0 位置是必输位置,而 1 2 和 k 这三个位置可以一步就走到0位置,所以这3个位置是必赢位置,可以递推出sg函数,通过打表来发现规律:
#include <iostream>
using namespace std;
int sg[1010];
int main(){
int t; cin>>t;
while(t--){
int n,k;
n=100;
cin>>k;
sg[0]=0;
sg[1]=1;
sg[2]=1;
for(int i=3;i<=n;i++){
if((i-k)>=0)
{
if(sg[i-1]==0||sg[i-2]==0||sg[i-k]==0)
{
sg[i]=1;
}
}else
{
if(sg[i-2]==0||sg[i-1]==0)
{
sg[i]=1;
}
}
}
for(int i=0;i<=n;i++){
cout<<i<<" "<<sg[i]<<endl;
}
}
return 0;
}
/*
2
5
0 0
1 1
2 1
3 0
4 1
5 1
6 0
7 1
8 1
9 0
10 1
11 1
12 0
13 1
14 1
15 0
16 1
17 1
18 0
19 1
20 1
21 0
22 1
23 1
24 0
25 1
6
0 0
1 1
2 1
3 0
4 1
5 1
6 1
7 1
8 1
9 1
10 1
11 1
12 0
13 1
14 1
15 0
16 1
17 1
18 1
19 1
20 1
21 1
22 1
23 1
24 0
25 1
*/
通过打表发现:
- 如果 k 不是 3 的倍数,那么只要位置是3的倍数就是必输位置,其他位置(除了0)都是必赢位置,所以判断 n 是否为 3 的倍数,若是,则先手必输,即Bob赢,否则,Alice赢。
- 如果 k 是 3 的倍数,那么 n 对 k+1 取模,如果取模后其值等于 k ,那么 n 位置必赢,即先手Alice必赢;如果取模后 n 不等于 k ,判断 n 是否为 3 的倍数,若不是,则先手Alice必赢,否则后手Bob必赢。
这个规律好难发现,看大佬的才知道!
Code(C++):
#include <iostream>
using namespace std;
int main(){
int t; cin>>t;
while(t--){
int n,k;
cin>>n>>k;
if(k%3){
if(n%3)
cout<<"Alice"<<endl;
else
cout<<"Bob"<<endl;
}else{
n%=(k+1);
if(n==k)
cout<<"Alice"<<endl;
else{
if(n%3)
cout<<"Alice"<<endl;
else
cout<<"Bob"<<endl;
}
}
}
return 0;
}