C
签到题
从后往前搜,每次搜最短的距离,然后取最长,O(Tn^2)
D
就是一纸老虎题,但又因为数组开小RE,线段树开4倍开4倍!!!
操作2本质上是将最大位前移,也就是乘2(如果是0则不动所以也是*2),操作1是砍掉一个最小位,操作3就是区间查询。
于是可以建立两个线段树,第一棵维护最大位,只有*2(操作2)和*0(对只有最大位的数进行操作1);第二棵维护后面的位(因为砍掉一位是单点修改),也可以用树状数组维护,操作1则是暴力枚举不为0的数砍掉(因为每个数最多只会被执行30次操作1)。时间复杂度是O(nlog(a[i])logn)

#include<bits/stdc++.h> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; const int N=1e5+7,mod=998244353; int n,a[N],b[N],c[N],s[N],pre[N],nxt[N],lazy[N<<2],sum[N<<2]; void add(int x,int v){while(x<=n)c[x]+=v,x+=x&-x;} int ask(int x){int ret=0;while(x)ret+=c[x],x-=x&-x;return ret;} void adds(int x,int v){while(x<=n)s[x]=(s[x]+v)%mod,x+=x&-x;} int asks(int x){int ret=0;while(x)ret=(ret+s[x])%mod,x-=x&-x;return ret;} void build(int l,int r,int rt) { lazy[rt]=1; if(l==r){sum[rt]=b[l];return;} int mid=l+r>>1; build(lson),build(rson); sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod; } void pushdown(int rt) { if(lazy[rt]!=1) { int c=lazy[rt]; lazy[rt]=1; lazy[rt<<1]=1ll*lazy[rt<<1]*c%mod; lazy[rt<<1|1]=1ll*lazy[rt<<1|1]*c%mod; sum[rt<<1]=1ll*sum[rt<<1]*c%mod; sum[rt<<1|1]=1ll*sum[rt<<1|1]*c%mod; } } void update(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R){sum[rt]=1ll*sum[rt]*c%mod,lazy[rt]=1ll*lazy[rt]*c%mod;return;} pushdown(rt); int mid=l+r>>1; if(L<=mid)update(L,R,c,lson); if(R>mid)update(L,R,c,rson); sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod; } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R)return sum[rt]; pushdown(rt); int mid=l+r>>1,ret=0; if(L<=mid)ret=(ret+query(L,R,lson))%mod; if(R>mid)ret=(ret+query(L,R,rson))%mod; return ret; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;++i)c[i]=s[i]=0,pre[i]=i-1,nxt[i]=i+1; pre[n+1]=n,nxt[0]=1; for(int i=1;i<=n;++i) { scanf("%d",&a[i]); add(i,1); for(int j=29;~j;--j)if((a[i]>>j)&1) { b[i]=(1<<j),a[i]-=(1<<j); break; } } build(1,n,1); for(int i=1;i<=n;++i)if(a[i])adds(i,a[i]); int Q,op,l,r,ans;scanf("%d",&Q); while(Q--) { scanf("%d%d%d",&op,&l,&r); if(op==1)printf("%d ",((query(l,r,1,n,1)+asks(r))%mod-asks(l-1)+mod)%mod); else if(op==3)update(l,r,2,1,n,1); else{ int pos=r+1,L=l,R=r,mid; while(L<=R) { mid=L+R>>1; if(ask(mid)-ask(L-1))pos=mid,R=mid-1; else L=mid+1; } while(pos<=r) { if(!a[pos]) { add(pos,-1); nxt[pre[pos]]=nxt[pos]; pre[nxt[pos]]=pre[pos]; update(pos,pos,0,1,n,1); } else{ adds(pos,mod-(a[pos]&-a[pos])); a[pos]-=a[pos]&-a[pos]; } pos=nxt[pos]; } } } } }
F
签到题
每次取gcd等价于每次砍掉至少一个因子,于是可以等价于把a[i]变成d(a[i]),即a[i]的因子数,然后看异或起来是否是0即可。
但暴力搜质因数会超时,要把根号以内的质因数筛出来减小搜索范围。
zz的我把a数组也开成了质数大小(即4000)导致RE了一发

#include<bits/stdc++.h> using namespace std; const int N=1e6+7; int n,cnt,pri[N],a[N]; int main() { for(int i=2;i<=4000;++i) { int flag=1; for(int j=2;j*j<=i;++j)if(i%j==0){flag=0;break;} if(flag)pri[++cnt]=i; } int T;scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1,x;i<=n;++i) { a[i]=0; scanf("%d",&x); for(int j=1;pri[j]*pri[j]<=x;++j) if(x%pri[j]==0) { while(x%pri[j]==0)x/=pri[j],++a[i]; } if(x>1)++a[i]; } int sum=0; for(int i=1;i<=n;++i)sum^=a[i]; if(!sum)puts("Bob");else puts("Alice"); } }
I
这种统计出现多少次的自然想到AC自动机,于是就是个模板题。每次记录下串长和上次出现的位置,加起来不超过i即可

#include<bits/stdc++.h> using namespace std; const int N=1e5+7,M=3e6+7; int n,cnt,id[N],ch[M][26],val[M],fail[M],lst[M],len[M],ans[M]; char s[N],buf[40]; int newnode(int l) { int x=++cnt; memset(ch[x],0,sizeof(ch[x])); len[x]=l; val[x]=fail[x]=lst[x]=ans[x]=0; return x; } int insert() { int u=1,n=strlen(buf+1); for(int i=1;i<=n;i++) { if(!ch[u][buf[i]-'a'])ch[u][buf[i]-'a']=newnode(i); u=ch[u][buf[i]-'a']; } ++val[u],lst[u]=-1; return u; } void build() { queue<int>q;q.push(1); while(!q.empty()) { int u=q.front();q.pop(); for(int i=0;i<26;i++) if(ch[u][i]) { int v=fail[u]; while(v&&!ch[v][i])v=fail[v]; fail[ch[u][i]]=v?ch[v][i]:1; q.push(ch[u][i]); } } } void query() { int u=1,n=strlen(s+1); for(int i=1;i<=n;i++) { while(u&&!ch[u][s[i]-'a'])u=fail[u]; u=u?ch[u][s[i]-'a']:1; int x=u; do{ if(val[x]&&(lst[x]==-1||lst[x]+len[x]<=i))lst[x]=i,++ans[x]; x=fail[x]; }while(x); } } int main() { int T;scanf("%d",&T); while(T--) { cnt=0,newnode(0); scanf("%s%d",s+1,&n); for(int i=1;i<=n;i++)scanf("%s",buf+1),id[i]=insert(); build(); query(); for(int i=1;i<=n;i++)printf("%d ",ans[id[i]]); } }
持续更新中……