牛客练习赛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;
}