牛客练习赛45

A-QAQ

题意:给一个长度为 N 的字符串S, 求S中不含相邻字符且长度为的"QAQ"子序列个数.
题解:把'Q'的个数做前缀和后缀和处理,a[] 存储'Q'个数的前缀和,b[]存储'Q'个数后缀和,如果第i个字符是'A',那么这时的个数为a[i-2] * b[i+2],枚举每一个'A',求和即可.

#include <bits/stdc++.h>
using namespace std;
const int N=5e3+5;
char s[N];
int a[N],b[N];
typedef long long ll;
int main(){
	scanf("%s",s+1);
	int n=strlen(s+1);
	for(int i=1;i<=n;i++){
		if(s[i]=='Q') a[i]=a[i-1]+1;
		else a[i]=a[i-1];
		if(s[n-i+1]=='Q') b[n-i+1]=b[n-i+2]+1;
		else b[n-i+1]=b[n-i+2];	
	}
	ll ans=0;
	for(int i=3;i<=n-2;i++){
		if(s[i]=='A') ans+=1ll*a[i-2]*b[i+2];
	}
	cout<<ans<<endl;
	return 0;
}
tips:实际上可以不用预先计算前缀和,可以边处理边计算前缀和.
#include <bits/stdc++.h>
using namespace std;
const int N=5e3+5;
char s[N];
int b[N];
typedef long long ll;
int main(){
	scanf("%s",s+1);
	int n=strlen(s+1);
	for(int i=1;i<=n;i++){
		if(s[n-i+1]=='Q') b[n-i+1]=b[n-i+2]+1;
		else b[n-i+1]=b[n-i+2];	
	}
	ll ans=0;
	int cnt=(s[1]=='Q')+(s[2]=='Q');
	for(int i=3;i<=n-2;i++){
		if(s[i]=='A') ans+=1ll*(s[i-1]=='Q'?cnt-1:cnt)*b[i+2];
		cnt+=s[i]=='Q';
	}
	cout<<ans<<endl;
	return 0;
}

B-Tic-Tac-Toe

题意:求Alice(白棋)能不能在下一步取得胜利,如果不能,输出"Bob",如果可以赢,但是Bob取走其中某个白棋后,Alice不能赢,则输出"Emmm",如果不管取走哪个都能赢,输出"Alice".(如果棋盘已满,Alice不能赢).
题解:

1) :

先判断每行每列,对角线是否存在两个'W'和一个'#',如果都不存在,说明一定不能赢.否则跳到2).

2) :

开始取走白棋,枚举每个白棋,判断在没有这个白棋时,Alice是否可以赢(判断方式与1)一样).如果在取走某个白棋后,Alice必输,则输出"Emmm".否则跳到3).

3):

不管取走哪个白棋,Alice都会赢,输出"Alice".

#include <bits/stdc++.h>
using namespace std;
char s[5][5];
int ck(){//判断是否可以赢 
	int cnt=0;
	int f=0;
	//每行 
	for(int i=1;i<=3;i++){
		cnt=0,f=0;
		for(int j=1;j<=3;j++){
			cnt+=s[i][j]=='W';
			if(s[i][j]=='#') f=1;
		}
		if(cnt==2&&f) return 1;
	}
	//每列 
	for(int i=1;i<=3;i++){
		cnt=0,f=0;
		for(int j=1;j<=3;j++){
			cnt+=s[j][i]=='W';
			if(s[j][i]=='#') f=1;
		}
		if(cnt==2&&f) return 1;
	}
	//对角线 
	cnt=0,f=0;
	cnt+=(s[1][1]=='W')+(s[2][2]=='W')+(s[3][3]=='W');
	f=(s[1][1]=='#')+(s[2][2]=='#')+(s[3][3]=='#');
	if(cnt==2&&f) return 1;
	cnt=0,f=0;
	cnt+=(s[3][1]=='W')+(s[2][2]=='W')+(s[1][3]=='W');
	f=(s[3][1]=='#')+(s[2][2]=='#')+(s[1][3]=='#');
	if(cnt==2&&f) return 1;
	return 0;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		scanf("%s",s[1]+1);scanf("%s",s[2]+1);scanf("%s",s[3]+1);
		if(!ck()) puts("Bob");
		else{
			int f=1;
			for(int i=1;i<=3;i++)
				for(int j=1;j<=3;j++)
					if(s[i][j]=='W'){
						s[i][j]='B';
						if(!ck()){
							f=0;
						}
						s[i][j]='W';
					}
			if(f) puts("Alice");
			else puts("Emmm");					
		} 
	}
	return 0;
}

C-Buy Fruits

题意:给你一组n个数,是[0,n-1]的一个排列,记为a,让你输出一组n个数,也是[0,n-1]的一个排列,记为b.使得每一个a[i]+b[i]值在[1,n-1]内,且只有某一个数重复一次.
题解:瞎搞找了个规律. 如果n为奇数(除了1,),输出 -1(1输出 0),如果n为偶数,b[0]=1,b[n/2]=0,b[i]=n-i-i,b[n-i+1]=(n+1)-a[i].如n=4, b[] =1, 2, 0, 3.

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N];
int vis[N];
int main(){
	int n;
	cin>>n;
	if(n==1){
		printf("0\n");
		return 0;
	}
	if(n&1){
		puts("-1");
		return 0;
	}
	else{
		a[0]=1;
		for(int i=1;i<=n/2;i++){
			if(i*2==n) a[i]=0;
			else{
				a[i]=n-i-i;
				a[n-i]=(n+1)-a[i];
			}
		}
	}
	for(int i=0;i<n;i++){
		printf("%d%c",a[i],i==n-1?'\n':' ');
	}
	return 0;
	
}
posted @ 2019-05-03 22:59  _yjun  阅读(363)  评论(0编辑  收藏  举报