191101-模拟测试11

mac2025-12-20  7

191101-模拟测试11

T1 queue

题目描述

解析

一道智障题目(话说我没做出来,是不是更智障 ) 对于第一个规定,预处理出所有组的最大公约数,然后每次询问直接计算是不是最大公约数的因数即可 对于第二个规定,预处理出所有组中最小的值的平方根即可

题解

#include<bits/stdc++.h> using namespace std; long long a[1000009],d,x,b,k,minx,n,q,stnd; long long read() { int f=1; long long re=0; char ch; for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0'; return re*f; } long long gcd(long long x,long long y) { if(y==0) return x; return gcd(y,x%y); } int main() { n=read(); minx=1e18; for(int i=1;i<=n;i++) { a[i]=read(); minx=min(minx,a[i]); } q=read(); d=a[1]; for(int i=2;i<=n;i++) d=gcd(d,a[i]); long long k=sqrt(minx); if(k*k==minx) stnd=k; else stnd=k+1; for(int i=1;i<=q;i++) { x=read(); b=read(); if(b==1) { if(d%x==0) printf("Yes\n"); else printf("No\n"); } if(b==2) { if(x>=stnd) printf("No\n"); else printf("Yes\n"); } } return 0; }

T2

题目描述

解析

题目描述一大堆,但其实题意非常简单,即统计与询问部分出现次数相同的元素种数相同的子串个数。(注意数组清空的技巧,不要全memset)

题解

#include<bits/stdc++.h>//正解 #define M 2009 using namespace std;//bj[]表示询问字串的出现次数相同的元素个数 int vis[M],bj[M],cnt[M],tot[M],num[M],ans,n,m,t,q,l,r,len; char s[M];//num[]表示查找子串的出现次数相同的元素个数 inline int read() { int f=1; int re=0; char ch; for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0'; return re*f; } bool check() { bool pd=0; for(int i=1;i<=m;i++) if(num[tot[i]]!=bj[tot[i]]) { pd=1; break; } if(pd) return false; return true; } int main() { t=read(); while(t--) { n=read(); q=read(); scanf("%s",s+1); for(register int i=1;i<=q;i++) { for(int j=0;j<26;j++) { vis[j]=0; cnt[j]=0; } ans=0; m=0; l=read(); r=read(); len=r-l+1; for(register int j=l;j<=r;j++) { vis[s[j]-'a']++; bj[vis[s[j]-'a']-1]--; bj[vis[s[j]-'a']]++; } for(register int j=1;j<=n;j++) if(bj[j]) { num[j]=0;//对该次要使用的数组清空 tot[++m]=j; } for(register int j=1;j<=len;j++) { cnt[s[j]-'a']++; num[cnt[s[j]-'a']-1]--; num[cnt[s[j]-'a']]++; } if(check()) ans++; for(register int j=len+1;j<=n;j++) { cnt[s[j]-'a']++; num[cnt[s[j]-'a']-1]--; num[cnt[s[j]-'a']]++; cnt[s[j-len]-'a']--; num[cnt[s[j-len]-'a']+1]--; num[cnt[s[j-len]-'a']]++; if(check()) ans++; } printf("%d\n",ans); for(register int j=1;j<=m;j++) { bj[tot[j]]=0; tot[j]=0; } } } return 0; }

T3 forever

解析

简化题意

关于 f i f_i fi:本质就是求以 i i i为根的子树的 ∑ a i ∑a_i ai

关于路径:本质就是可以从 i i i出发,到达任何不在以 i i i为根的子树里的,权值比 i i i小的节点。

题解

首先,我们考虑如何计算 f i f_i fi 这是一个经典的入门树形dp问题,直接按照含义转移即可 f i = a i + ∑ f j f_i=a_i+∑f_j fi=ai+fj( j j j i i i的子节点)

然后,我们考虑如何来计算 g i g_i gi 由于按位或运算每一个二进制位是互不干扰的,所以我们可以对于每一个二进制位分别考虑答案是多少,再累加起来。

所以,我们现在来一位位考虑。

一个关于按位或的基础性质:如果这些数当中有一个在这一位上是1,那按位或起来的结果在这一位上就是1;否则是0。

首先,因为 g i g_i gi是所有 f j f_j fj值比 f i f_i fi小的,且不在以 i i i为根的子树中的fj的和。我们立马就会想到可以按照fi排序,那样我们按照 f i f_i fi由小到大处理,统计到 f i f_i fi的时候就可以统计出所有比 f i f_i fi小的f,在当前处理的这一二进制位上1的个数cnt。

由于在 i i i的子树中,所有节点的f值都小于 f i f_i fi,所以我们这个cnt要减去以i为根的子树中(不包括i自己)在当前二进制位下1的个数 h i h_i hi 如果cnt大于0,我们就可以知道 g i g_i gi在当前这一二进制位下是1。

至于 h i h_i hi,使用类似于 f i f_i fi的方法统计即可。

时间复杂度就是 O ( n l o g n O(nlogn O(nlogn)

题解

#include<bits/stdc++.h> #pragma comment(linker, "/STACK:102400000,102400000") #define M 500009 using namespace std; long long cnt,in[M],out[M],n,imp,to[M*2],nxt[M*2],tot,first[M],ans[M],h[M][25],sum[M][25]; struct zb { long long x,num; }f[M]; bool comp(const zb &a,const zb &b) { return a.x<b.x; } long long read() { int f=1; long long re=0; char ch; for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0'; return re*f; } void add(long long x,long long y) { nxt[++tot]=first[x]; first[x]=tot; to[tot]=y; } void dfs1(long long r,long long fa) { in[r]=++cnt; for(int i=first[r];i;i=nxt[i]) { long long v=to[i]; if(v==fa) continue; dfs1(v,r); f[r].x+=f[v].x; for(int k=0;k<=22;k++) h[r][k]+=(h[v][k]+((f[v].x&(1<<k))?1:0));//注意三目要在外面套一层括号 } out[r]=cnt; return; } int main() { int size=40<<20; freopen("forever.in","r",stdin); //freopen("forever.out","w",stdout); __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//扩栈 long long x,y; n=read(); imp=read(); for(int i=1;i<=n-1;i++) { x=read(); y=read(); add(x,y); add(y,x); } for(int i=1;i<=n;i++) { f[i].x=read(); f[i].num=i; } dfs1(imp,0); sort(f+1,f+n+1,comp); for(int i=1;i<=n;i++) for(int j=0;j<=22;j++) sum[i][j]=sum[i-1][j]+(f[i].x&(1<<j)?1:0);//维护前缀和 for(int i=n;i>=1;i--) { int head=i; while(f[head].x==f[head-1].x) head--; for(int j=head;j<=i;j++) { int su=0; for(int z=0;z<=22;z++) { int cz=sum[head-1][z]-h[f[j].num][z]; su=(cz)?(su+(1<<z)):su; } ans[f[j].num]=su; } i=head; } for(int i=1;i<=n;i++) printf("%lld ",ans[i]); exit(0); }

n 2 n^2 n2暴力代码

#include<bits/stdc++.h> #define M 500009 using namespace std; long long cnt,in[M],out[M],n,imp,to[M*2],nxt[M*2],tot,first[M],ans[M]; bool vis[M]; struct zb { long long x,num; }f[M]; bool comp(const zb &a,const zb &b) { return a.x<b.x; } long long read() { int f=1; long long re=0; char ch; for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0'; return re*f; } void add(long long x,long long y) { nxt[++tot]=first[x]; first[x]=tot; to[tot]=y; } void dfs1(long long r,long long fa) { in[r]=++cnt; for(int i=first[r];i;i=nxt[i]) { long long v=to[i]; if(v==fa) continue; dfs1(v,r); f[r].x+=f[v].x; } out[r]=cnt; return; } int main() { //freopen("forever.in","r",stdin); //freopen("forever.out","w",stdout); long long x,y; n=read(); imp=read(); for(int i=1;i<=n-1;i++) { x=read(); y=read(); add(x,y); add(y,x); } for(int i=1;i<=n;i++) { f[i].x=read(); f[i].num=i; } dfs1(imp,0); sort(f+1,f+n+1,comp); for(int i=1;i<=n;i++) for(int j=1;j<i;j++) { if(in[f[j].num]>=in[f[i].num]&&in[f[j].num]<=out[f[i].num]) continue; if(f[j].x==f[i].x) continue; ans[f[i].num]|=f[j].x; } for(int i=1;i<=n;i++) printf("%lld ",ans[i]); return 0; }
最新回复(0)