由于不是修仙党看见晚上12点开还3个小时就没打,后来线下开虚拟赛打的...估计现场打能涨不少分?
不过现场状态会更好还是更坏也说不定
A. Perfect Squares
题意: 求给定集合中最大的完全平方数 n<=1000 |ai|<=1000000
Sol:签到,我硬是没看见有负数WA了一发
Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000009;
int vis[maxn];
int n,ans=-10000000;
int main()
{
cin>>n;
for(int i=0;i<=1000;i++) vis[i*i]=1;
for(int i=1;i<=n;i++)
{
int x;cin>>x;
if(x<0) ans=max(ans,x);
else if(!vis[x]) ans=max(ans,x);
}
cout<<ans<<endl;
return 0;
}
B. Conan and Agasa play a Card Game
题意:n张纸牌上有数,Alice柯南和Morisa\Bob阿笠博士轮流操作,每次选一张牌,把所有严格<这张牌的牌和他本身拿走,无法操作输,问先手是否必胜
Sol:如果最大的有奇数张,先手胜,否则谁先最大的谁输,可以转化为去掉最大值后的子游戏,有奇数先手必胜,否则后手胜
Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000009;
int cnt[maxn],a[maxn];
int n;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main()
{
n=read();
for(int i=1;i<=n;i++) a[i]=read(),cnt[a[i]]++;
bool flag=0;
for(int i=100000;i>=1;i--) if(cnt[i]%2) flag=1;
if(flag) puts("Conan");
else puts("Agasa");
return 0;
}
C. Travelling Salesman and Special Numbers
题意:定义f(x)=|x二进制位中1的个数|,n以内操作恰好k次变成1的数的个数 n<=2^1000 k <=1000
Sol:先dp出来1000以内每个数几次会变成1,规定1进行0次操作变成1,设为g(x),枚举1000以内g(x)==k-1的数,转化为求n以内二进制位有x个1的数的个数,经典数位DP问题,需要特判k=0和k=1
Code:
#include<bits/stdc++.h>
#define debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
const int maxn = 1009;
const int mod = 1e9+7;
int f[maxn],a[maxn],C[maxn][maxn];
int n,m,ans,tot;
char str[maxn];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int calc(int x)
{
int res=0;
while(x){if(x&1)res++;x>>=1;}
return res;
}
void work(int x)
{
int cnt=0;
for(int i=n;i>=1;i--)
{
if(a[i])
{
if(x>=cnt) ans=(ans+C[i-1][x-cnt])%mod;
cnt++;
}
}
if(x==tot) ans=(ans+1)%mod;
}
int main()
{
scanf("%s%d",str+1,&m);n=strlen(str+1);
for(int i=1;i<=n;i++) a[i]=str[i]-'0',tot+=a[i];
reverse(a+1,a+1+n);
for(int i=0;i<=n;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
f[1]=1;
for(int i=2;i<=1000;i++) f[i]=f[calc(i)]+1;
if(m==0) puts("1");
else
{
for(int i=1;i<=1000;i++) if(f[i]==m) work(i);
printf("%d\n",(ans-(m==1)+mod)%mod);
}
return 0;
}
D. Bash and a Tough Math Puzzle
题意:给定正整数序列,两种操作:
1.输入l,r,k 询问区间[l,r]是否可以最多改变一个数使gcd==k
2.输入x,y 讲a[x]改成y
Sol:可以转化为区间中多少个数是k的倍数----不可做
但是最多1个数不是就可以GG了,维护区间gcd,当一个范围内大区间gcd不是k的倍数意味着里面肯定至少有一个数不是,暴力递归下去找,最多暴力找2次就没了,复杂度O(nlog^2n)
Code:
#include<bits/stdc++.h>
#define debug(x) cout<<#x<<"="<<x<<endl
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn = 500009;
const int mod = 1e9+7;
struct sg_tree{int val;}node[maxn<<2];
int n,m,q,cnt;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int gcd(int x,int y)
{
if(y==0) return x;
return gcd(y,x%y);
}
void update(int rt){node[rt].val=gcd(node[rt<<1].val,node[rt<<1|1].val);}
void build(int l,int r,int rt)
{
if(l==r)
{
node[rt].val=read();
return ;
}int mid=(l+r)>>1;
build(lson);build(rson);
update(rt);
}
void insert(int l,int r,int rt,int pos,int delta)
{
if(l==r)
{
node[rt].val=delta;
return ;
}int mid=(l+r)>>1;
if(pos<=mid) insert(lson,pos,delta);
else insert(rson,pos,delta);
update(rt);
}
void query(int l,int r,int rt,int left,int right,int delta)
{
if(cnt<0) return ;
if(l==r)
{
if(node[rt].val%delta) cnt--;
return ;
}
if(l==left&&right==r) if(node[rt].val%delta==0) return ;
int mid=(l+r)>>1;
if(right<=mid) query(lson,left,right,delta);
else if(left>mid) query(rson,left,right,delta);
else query(lson,left,mid,delta),query(rson,mid+1,right,delta);
}
int main()
{
n=read();
build(1,n,1);
m=read();
while(m--)
{
int opt=read();
if(opt==1)
{
int l=read(),r=read(),x=read();
cnt=1;
query(1,n,1,l,r,x);
if(cnt>=0) puts("YES");
else puts("NO");
}
else
{
int x=read(),y=read();
insert(1,n,1,x,y);
}
}
return 0;
}
E. Palindromes in a Tree
题意:一棵树,点上有字符,一条路径是好的当路径上的字符可以搞成回文的,求经过每个点的好路径的个数 n<=200000 字符集a-t
Sol:数一数发现字符集只有20,而可以搞成回文意味着每个字符的出现次数最多只有一个奇数,考虑装压每个字母奇偶性,而树上路径问题一般考虑点分治,找到重心,现在计算经过重心的路径对每个点的贡献,用cnt[i]记录i状态的数量,先把子树信息统计进去,再枚举每个子树,先删掉这个子树信息,统计以每个点为结尾的好路径个数,因为经过就会算贡献所以要把子树信息上传,最后再把信息加回来,复杂度O(nlogn*σ)
Code:
#include<bits/stdc++.h>
#define debug(x) cout<<#x<<"="<<x<<endl
typedef long long ll;
using namespace std;
const int maxn = 200009;
int first[maxn],siz[maxn],W[maxn],a[maxn];
ll ans[maxn];
int cnt[1<<21],sta[maxn];
struct edg{int next,to;}e[maxn<<1];
bool vis[maxn];
int n,tot,rt,sum,e_sum;
char str[maxn];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void add_edg(int x,int y)
{
e_sum++;
e[e_sum].next=first[x];
first[x]=e_sum;
e[e_sum].to=y;
}
ll calc(int x,int val)
{
ll res=0;
for(int i=1;i<=tot;i++) res+=cnt[val^sta[i]];
return res;
}
void find(int x,int fa)
{
siz[x]=1;W[x]=0;
for(int i=first[x];i;i=e[i].next)
{
int w=e[i].to;
if(w==fa||vis[w]) continue;
find(w,x);
siz[x]+=siz[w];
W[x]=max(W[x],siz[w]);
}W[x]=max(W[x],sum-siz[x]);
if(W[x]<W[rt]) rt=x;
}
void add(int x,int fa,int val,int opt)
{
val^=(1<<a[x]);
cnt[val]+=opt;
for(int i=first[x];i;i=e[i].next)
{
int w=e[i].to;
if(w==fa||vis[w]) continue;
add(w,x,val,opt);
}
}
ll work(int x,int fa,int val)
{
val^=(1<<a[x]);
ll res=calc(x,val);
for(int i=first[x];i;i=e[i].next)
{
int w=e[i].to;
if(w==fa||vis[w]) continue;
res+=work(w,x,val);
}
ans[x]+=res;
return res;
}
void solve(int x)
{
vis[x]=1;
cnt[1<<a[x]]++;
for(int i=first[x];i;i=e[i].next)
{
int w=e[i].to;
if(vis[w]) continue;
add(w,x,1<<a[x],1);
}
ll res=calc(rt,0);
for(int i=first[x];i;i=e[i].next)
{
int w=e[i].to;
if(vis[w]) continue;
add(w,x,1<<a[x],-1);
res+=work(w,x,0);
add(w,x,1<<a[x],1);
}
ans[x]+=res/2;
for(int i=first[x];i;i=e[i].next)
{
int w=e[i].to;
if(vis[w]) continue;
add(w,x,1<<a[x],-1);
}
cnt[1<<a[x]]--;
for(int i=first[x];i;i=e[i].next)
{
int w=e[i].to;
if(vis[w]) continue;
sum=siz[w];rt=0;
find(w,0);solve(rt);
}
}
int main()
{
n=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
add_edg(x,y);add_edg(y,x);
}
scanf("%s",str+1);
for(int i=1;i<=n;i++) a[i]=str[i]-'a';
sta[++tot]=0;
for(int i=0;i<20;i++) sta[++tot]=1<<i;
rt=0;sum=n;W[0]=n+1;
find(1,0);solve(rt);
for(int i=1;i<=n;i++) printf("%I64d ",ans[i]+1);
return 0;
}
F. Substrings in a String
题意:一个字符串,两种操作:
1.输入x,y 把ch[x]改成y
2.输入l,r,str 询问[l-r]中str出现多少次
Sol:一开始完全不会...都开始想FFT了
旁边大爷吼了一句:"诶我去这题bitset暴力能过"
嘿嘿嘿
又刷新了我对复杂度的认知上线
Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100009;
bitset<maxn> c[30],uuz,ans;
int n,m;
char str[maxn],tmp[maxn];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main()
{
scanf("%s",str+1);n=strlen(str+1);
for(int i=1;i<=n;i++) c[str[i]-'a'][i]=1;
for(int i=0;i<=n;i++) uuz[i]=1;
m=read();
while(m--)
{
int opt=read();
if(opt==1)
{
int x=read();scanf("%s",tmp+1);
c[str[x]-'a'][x]=0;
c[tmp[1]-'a'][x]=1;
str[x]=tmp[1];
}
else
{
int l=read(),r=read();scanf("%s",tmp+1);
int len=strlen(tmp+1);
if(len>r-l+1) puts("0");
else
{
ans=uuz;
for(int i=1;i<=len;i++) ans&=(c[tmp[i]-'a']>>i);
printf("%d\n",(ans>>(l-1)).count()-(ans>>(r-len+1)).count());
}
}
}
return 0;
}
G. Sum the Fibonacci
题意:给一个序列求
- 1 ≤ a, b, c, d, e ≤ n
- (sa | sb) & sc & (sd ^ se) = 2i
- sa & sb = 0
f是斐波那契数列 i是任意自然数
的和mod 1e9+7
Sol: 没时间写了,,而且我也不会
后来知道是可以FWT硬上,条件3暴力枚举子集就行
等我会了FWT再回来补上...
学(bei)了FWT...
只考虑第二个条件,可以先求出cnt[x]表示x的个数,cor[x] 表示满足[sa|sb=x]的数对的数量,cxor[x]表示满足[sa^sb=x]的数对的数量
后两个可以用FWT做
然后把cor\cxor\cnt变成fib[cor\cxor\cnt]
再把这三个FWT起来,枚举i就可以了
考虑第三个条件,这是一个子集卷积(又不会)
但是可以3^log(n)暴力枚举子集,不做或卷积
复杂度O(3^log(n)+nlogn)
Code:
#include<bits/stdc++.h>
#define AND 1
#define OR 2
#define XOR 3
typedef long long ll;
using namespace std;
const int maxn = (1<<17)+9;
const ll mod = 1e9+7, inv = 5e8+4;
ll cnt[maxn],cor[maxn],cxor[maxn],fib[maxn],a[maxn],b[maxn];
int n,mr=maxn-9;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline ll MOD(ll x)
{
x%=mod;
if(x<0) x+=mod;
return x;
}
void fwt(ll *x,int opt,int type)
{
for(int i=1;i<mr;i<<=1)
for(int p=i<<1,j=0;j<mr;j+=p)
for(int k=0;k<i;k++)
{
ll L=x[j+k],R=x[j+k+i];
if(opt==AND) x[j+k]=MOD(L+R*type);
if(opt==OR) x[j+k+i]=MOD(R+L*type);
if(opt==XOR)
{
x[j+k]=MOD(L+R);x[j+k+i]=MOD(L-R);
if(type==-1) x[j+k]=x[j+k]*inv%mod,x[j+k+i]=x[j+k+i]*inv%mod;
}
}
}
int main()
{
n=read();
fib[1]=1;
for(int i=2;i<=mr;i++) fib[i]=MOD(fib[i-1]+fib[i-2]);
for(int i=1;i<=n;i++)
{
int x=read();
cnt[x]++;
}
for(int i=0;i<=mr;i++)
if(cnt[i])
{
int s=(mr-1)-i;
for(int j=s;;j=(j-1)&s)
{
cor[i|j]=MOD(cor[i|j]+1ll*cnt[i]*cnt[j]);
if(j==0) break;
}
}
memcpy(cxor,cnt,sizeof cxor);
fwt(cxor,XOR,1);
for(int i=0;i<=mr;i++) cxor[i]=MOD(cxor[i]*cxor[i]);
fwt(cxor,XOR,-1);
for(int i=0;i<=mr;i++)
{
cnt[i]=MOD(cnt[i]*fib[i]);
cor[i]=MOD(cor[i]*fib[i]);
cxor[i]=MOD(cxor[i]*fib[i]);
}
fwt(cnt,AND,1);fwt(cor,AND,1);fwt(cxor,AND,1);
for(int i=0;i<=mr;i++) cnt[i]=cnt[i]*cor[i]%mod*cxor[i]%mod;
fwt(cnt,AND,-1);
ll ans=0;
for(int i=0;i<=16;i++) ans=MOD(ans+cnt[1<<i]);
cout<<ans<<endl;
return 0;
}
最终成绩rk33 还行呀~