AtCoder Beginner Contest 349
ABC349 A - Zero Sum Game
代码(签到题)
#include <cstdio>
#include <cctype>
using namespace std;
int ans,n;
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int main(){
n=iut();
for (int i=1;i<n;++i) ans-=iut();
return !printf("%d",ans);
}
ABC349 B - Commencement
代码
#include <cstdio>
#include <cctype>
#include <cstring>
using namespace std;
int n,c[26],C[266]; char s[266];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int main(){
scanf("%s",s+1),n=strlen(s+1);
for (int i=1;i<=n;++i) ++c[s[i]-97];
for (int i=0;i<26;++i)
if (c[i]&&++C[c[i]]>2) return !printf("No");
for (int i=0;i<26;++i)
if (C[c[i]]==1) return !printf("No");
return !printf("Yes");
}
ABC349 C - Airport Code
分析
对于 \(X\) 结尾的,直接找到最前的第一个字母和最后的第二个字母(第一个字母在第二个字母前)判断是否存在\
否则就是找到最前的第一个字母和最后的第三个字母,接着在它们中间找到第二个字母是否存在
代码
#include <cstdio>
#include <cctype>
#include <cstring>
using namespace std;
const int N=100011;
int n,st,ed; char s1[N],s2[N];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int main(){
scanf("%s%s",s1+1,s2+1),n=strlen(s1+1);
for (int i=1;i<=n;++i)
if (s1[i]==s2[1]+32) {st=i; break;}
if (!st) return !printf("No");
if (s2[3]=='X'){
for (int i=st+1;i<=n;++i)
if (s1[i]==s2[2]+32) return !printf("Yes");
return !printf("No");
}
for (int i=n;i>st;--i)
if (s1[i]==s2[3]+32) {ed=i; break;}
if (!ed) return !printf("No");
for (int i=st+1;i<ed;++i)
if (s1[i]==s2[2]+32) return !printf("Yes");
return !printf("No");
}
ABC349 D - Divide Interval
分析
贪心就是让区间长度尽量取lowbit(l)就行了(其实类比于树状数组加lowbit的过程)
代码
#include <iostream>
using namespace std;
typedef long long lll;
lll L,R,m,l[1000011],r[1000011];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>L>>R,m=0;
if (!L){
l[++m]=0;
r[m]=1;
while (r[m]<=R) r[m]<<=1;
r[m]>>=1;
L=r[m];
}
while (L!=R){
lll lowbit=-L&L;
while (L+lowbit>R) lowbit>>=1;
l[++m]=L,r[m]=L+lowbit,L+=lowbit;
}
cout<<m<<'\n';
for (int i=1;i<=m;++i) cout<<l[i]<<' '<<r[i]<<'\n';
return 0;
}
ABC349 E - Weighted Tic-Tac-Toe
分析
必胜当且仅当对手必败,直接搜索所有可能状态即可,注意用总和判断终止需要将符号反向(因为选完数字必胜对应的是对手必输)
代码
#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;
typedef long long lll;
lll a[3][3]; int col[3][3];
bool check(){
for (int i=0;i<3;++i)
if (col[i][0]&&col[i][0]==col[i][1]&&col[i][1]==col[i][2]) return 1;
for (int i=0;i<3;++i)
if (col[0][i]&&col[0][i]==col[1][i]&&col[1][i]==col[2][i]) return 1;
if (col[0][0]&&col[0][0]==col[1][1]&&col[1][1]==col[2][2]) return 1;
if (col[0][2]&&col[0][2]==col[1][1]&&col[1][1]==col[2][0]) return 1;
return 0;
}
bool dfs(int dep){
if (dep>9){
lll sum=0,Sum=0;
for (int i=0;i<3;++i)
for (int j=0;j<3;++j)
if (col[i][j]==1) sum+=a[i][j];
else if (col[i][j]==2) Sum+=a[i][j];
return sum<=Sum;
}
for (int i=0;i<3;++i)
for (int j=0;j<3;++j)
if (!col[i][j]){
col[i][j]=(dep&1)?1:2;
if (check()){
col[i][j]=0;
return 1;
}else{
int now=dfs(dep+1);
col[i][j]=0;
if (!now) return 1;
}
}
return 0;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
for (int i=0;i<3;++i)
for (int j=0;j<3;++j) cin>>a[i][j];
if (dfs(1)) cout<<"Takahashi";
else cout<<"Aoki";
return 0;
}
ABC349 F - Subsequence LCM
分析
将 \(m\) 质因数分解,实际上取到最小公倍数当且仅当选取集合对于每个质因数至少有一个数与 \(m\) 的质因数指数相同,
\(m\) 最多由十三个质数组成,\(a_i\) 实际上提供的是一个二进制状态,也就是按位或为全1的集合个数,那么子集卷积再容斥就可以了
代码
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
using namespace std;
const int N=200011,M=8421,mod=998244353;
typedef long long lll; lll _k,k,p[M];
int n,ans,dp[M],xo[M],two[N],bl,m,c[M];
lll iut(){
lll ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void Mo(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
int main(){
n=iut(),_k=k=iut(),two[0]=1,bl=sqrt(k);
if (k==1){
ans=1;
for (int i=1;i<=n;++i)
if (iut()==1) Mo(ans,ans);
printf("%d",ans-1);
return 0;
}
for (int i=2;i<=bl;++i)
if (k%i==0){
int cnt=0;
while (k%i==0) ++cnt,k/=i;
p[m]=i,c[m++]=cnt;
}
if (k>1) p[m]=k,c[m++]=1;
for (int i=1;i<=m;++i) Mo(two[i]=two[i-1],two[i-1]);
for (int i=m+1;i<=n;++i) Mo(two[i]=two[i-1],two[i-1]);
for (int i=1;i<two[m];++i) xo[i]=xo[i&(i-1)]+1;
for (int i=1;i<=n;++i){
lll x=iut(); int S=0;
if (_k%x) continue;
for (int j=0;j<m;++j)
if (x%p[j]==0){
int cnt=0;
while (x%p[j]==0) x/=p[j],++cnt;
if (cnt==c[j]) S|=two[j];
}
++dp[S];
}
for (int i=0;i<m;++i)
for (int j=0;j<two[m];++j)
if ((j>>i)&1) dp[j]+=dp[j^two[i]];
for (int j=0;j<two[m];++j) dp[j]=two[dp[j]];
for (int j=0;j<two[m];++j)
if ((m-xo[j])&1) Mo(ans,mod-dp[j]);
else Mo(ans,dp[j]);
return !printf("%d",ans);
}
ABC349 G - Palindrome Construction
分析
实际上给定的半径和 Manacher 的形式很像,不妨利用 Manacher 填数,
限制条件就是边界两数不能相同,打个标记贪心填最小的,最后再用 Manacher 检验回文即可
代码
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
using namespace std;
const int N=200011; vector<int>K[N];
int n,a[N],b[N],mex[N],s[N<<1],p[N<<1],m;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
int main(){
n=iut();
int mx=0,mid=0;
for (int i=1;i<=n;++i){
a[i]=iut()+1;
if (i<mx) b[i]=b[mid*2-i];
else{
for (int j=K[i].size()-1;~j;--j) mex[K[i][j]]=i;
for (b[i]=1;mex[b[i]]==i;++b[i]);
}
if (mx<i+a[i]) mx=i+a[i],mid=i;
K[i+a[i]].push_back(b[i-a[i]]);
}
s[0]=0xcfcfcfcf,mx=mid=0;
for (int i=1;i<=n;++i) s[++m]=0x3f3f3f3f,s[++m]=b[i];
s[++m]=0x3f3f3f3f,s[++m]=0x7f7f7f7f;
for (int i=1;i<m;++i){
p[i]=(i<mx)?min(p[mid*2-i],mx-i):1;
while (s[i-p[i]]==s[i+p[i]]) ++p[i];
if (mx<i+p[i]) mx=i+p[i],mid=i;
if (!(i&1)&&a[i>>1]!=(p[i]>>1)) return !printf("No");
}
printf("Yes\n");
for (int i=1;i<=n;++i) print(b[i]),putchar(32);
return 0;
}