目录
D - Non Arithmetic Progression Set
A - AB Palindrome
给出一个由A和B构成的字符串,可以用AB替换其中的连续两个字符,并且可以替换多次,问是否能最终成为回文
由于可以替换多次,所以我们可以一点点想
无非就以下八种情况
A**A(总长为偶数),A***A(总长为奇数),B**B,B***B,B**A,B***A,A**B,A***B
A**A-> AB*A-> AABA-> ABBA
A***A-> AB**A-> ABABA
B**B-> BABA->BAAB
B***B-> BAB*B->BABAB
B**A-> BABA-> BAAB
B***A-> BABAB
而其余两种情况由于我们不能改变s0的A,也不能改变末尾的B,所以一定无解
综上总结一下,B开头A结尾除了BA外都可
代码如下
string s;
int n;
signed main()
{
cin>>n;
cin>>s;
if((s[0]=='A'&&s[n-1]=='B')||(s=="BA")) cout<<"No";
else cout<<"Yes";
}
B - AB Game
博弈论,说一共N回合,每回合有n个石头(1<=n<=N)Alice只能拿走A的倍数的石头,Bob只能拿走B的倍数的石头,问在双方都发挥最佳情况下,Alice赢多少局
首先我们分情况想
由于我们先拿,如果总的石头n小于a,那我们无论如何第一回合也拿不到,所以这种情况下我们是必输的,答案为 0
然后就是n大于a时候,也有两种情况,b大于等于a和b小于a,其中b>=a的情况是比较好考虑的
我们第一回合可以拿n/a *a个,使石头堆里剩余n%a个,n%a<=a 那他必然<=b,Bob就是必输的
所以n大于a且b大于等于a时 我们除了第一种情况(n<a)的区间,我们都是必赢的
所以这种情况答案是 n-a+1
之后就是最复杂的a>b,我们可以想象,如果我们拿了一次p*a之后,剩下的数小于b了,那Bob就输了,画成数轴就是这样
也就是对于任意 (因为要抛去第一段0-a,这段我们是必输的,所以-1)
我们可以赢 [p*a-p*a+b) 个回合,也就是b个
所以答案是(n/a(合法p的个数) -1)* b
还漏掉最后一块也就是 n%a 这一段,而这一段又有两种情况
一种是n%a大于等于b,一种小于b
而对于上面情况 结合以上分析,我们只可以赢 [p*a,p*a+b)个回合,也就是b个
下面情况 我们可以赢 n%a+1 个回合
所以最后答案要再加上一个
min(n%a+1,b)
三种情况讨论完,代码如下
int n,a,b;
signed main() {
cin>>n>>a>>b;
if(a>n) cout<<0;
else if(a<=b) cout<<n-a+1;
else cout<<(n/a-1)*b+min(n%a+1,b);
}
C - Split and Maximize
题目说让我们把1-2*N 这个排列分成两组长为N的序列,使得他们的叉积最大,问有多少种排列方式可以得到这个最大的叉积
首先我们要明白一个前置条件
当 A<B<C<D 时
有 A*D + B*C < A*C + B*D < C*D + A*B
例如1234吧 10<11<14
我们推广到2*N的序列,不难想象这个最大的叉积是由
(2*N)*(2*N-1)+(2*N-2)*(2*N-3).........2*1
也就是要2*N和2*N-1对应,2*N-2要和2*N-3对应.....
这就转化为一个排列组合问题
我们知道,一共有N个空位,一旦A中的第i位确定了,则B中第i位也被确定(因为要一一对应)
所以对于每个空位,总的排列有2的N次幂种
而对于N个空位,每个位置依次选择,有种选择
所以答案为
代码如下
const int mod=998244353;
int qpow(int a,int b,int p){
int res=1%p;
while(b){
if(b&1) res=res*1ll*a%p;
a=a*1ll*a%p;
b>>=1;
}
return res;
}
signed main() {
int n;
int ans=1;
cin>>n;
ans=qpow(2,n,mod);
for(int i=n+2;i<=2*n;i++){
ans=ans*i;
ans%=mod;
}
cout<<ans<<endl;
return 0;
}
D - Non Arithmetic Progression Set
题意为给你个N,给一个M,让我们构造一个长度为N的序列,使得总和为M
并且对于任意三元组 y-x!=z-y
我们可以变幻以下式子,给他变成 2*y=x+z
也就是对于任意三元组,任意两个数加起来不等于x+z
怎么构造呢,我们可以基于三进制考虑
如果我们在三进制情况下,选择只由0和1构成的数(三进制中只有012)
这样2*y在三进制下就会只由0和2构成
而对于x+y,也只由2和0构成的数,因为原数字由01构成,加法时没有进位
这样要想x+z==2*y,只有x==y==z时才能成立,也就是我们选择不同的这样的数,构造出来的序列就天然满足条件
接下来就是考虑M的限制了
我们可以在最开始的第一个数从0开始选,这样以后加或减的时候得数仍在-1e7-1e7之间
然后我们通过调整数字,就可以满足m
这题代码有点抽象
const int N=10010;
int n,m,a[N];
signed main(){
scanf("%lld%lld",&n,&m);
int sum=0;
for(int i=0;i<n-1;i++){
for(int j=0,b=1;j<15;j++,b*=3){
if(i>>j&1){
a[i+1]+=b;
}
}
sum+=a[i+1];
}
int r=(m-sum)%n;
a[n]=(a[n-1]*3+n)/n*n+r;
int d=(m-a[n]-sum)/n;
for(int i=1;i<=n;i++){
cout<<a[i]+d<<endl;
}
}