2024初三年前集训测试2
2024初三年前集训测试2
上海
-
简化题意:给定一个正整数
,求最小的正整数 满足 ,如无解则输出-1
。- 类似 CF1444A Division 。
-
当
时,显然无解。 -
当
时,由算术基本定理设 ,容易得最小的正整数解 一定满足 ,其中 。当 时,无解;否则构造 即可,最终 即为所求。点击查看代码
ll prime[100000],c[100000],cnt=0; void divide(ll n) { for(ll i=2;i<=sqrt(n);i++) { if(n%i==0) { cnt++; prime[cnt]=i; while(n%i==0) { c[cnt]++; n/=i; } } } if(n>1) { cnt++; prime[cnt]=n; c[cnt]++; } } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); ll k,n=-1,sum=0,i; cin>>k; divide(k); for(i=1;i<=cnt;i++) { sum+=(c[i]==1); } if(k!=1&&sum!=cnt) { n=1; for(i=1;i<=cnt;i++) { n*=pow(prime[i],(ll)(ceil(1.0*c[i]/2))); } } cout<<n<<endl; fclose(stdin); fclose(stdout); return 0; }
华二
-
部分分
:因有 ,令 分别表示 出现的次数。然后就转化成了多重集的排列数,全排列个数为 。
-
正解
- 注意到
,考虑利用这个性质。 - 除了相等的数不能交换其余都是能够进行随便交换,交换两个相等的数等价于不交换,故一个数可以放到任何位置。
与其他任何数都互质,故可以放到任何位置,最后再进行处理。 中只有 与其他数都不互质,故两个 之间的数一定不能交换出去,等价于 的位置已经被固定了,设原来的数列就被 分成了 个区间。 不能相互交换,相对位置(每两个数之间放其他的数的个数不固定)不变; 不能相互交换,相对位置(每两个数之间放其他的数的个数不固定)不变。- 设第
个区间内 出现的次数为 ,第 个区间内 出现的次数为 , 分别表示 出现的次数。容斥后有 即为所求。
点击查看代码
ll a[100001],jc[100001],inv[100001],jc_inv[100001]; ll A(ll n,ll m,ll p) { return (n>=m&&n>=0&&m>=0)?jc[n]*jc_inv[n-m]%p:0; } ll C(ll n,ll m,ll p) { return (n>=m&&n>=0&&m>=0)?(jc[n]*jc_inv[m]%p)*jc_inv[n-m]%p:0; } int main() { freopen("b.in","r",stdin); freopen("b.out","w",stdout); ll n,ans=1,sum1=0,sum2=0,sum3=0,sum4=0,sum5=0,i,p=998244353; cin>>n; inv[1]=1; jc[0]=jc_inv[0]=jc[1]=jc_inv[1]=1; for(i=2;i<=n;i++) { inv[i]=(p-p/i)*inv[p%i]%p; jc[i]=jc[i-1]*i%p; jc_inv[i]=jc_inv[i-1]*inv[i]%p; } for(i=1;i<=n;i++) { cin>>a[i]; sum1+=(a[i]==2||a[i]==4||a[i]==8); sum2+=(a[i]==3||a[i]==9); sum3+=(a[i]==1); sum4+=(a[i]==5); sum5+=(a[i]==7); if(a[i]==6||i==n) { ans=ans*C(sum1+sum2+1-1,sum2+1-1,p)%p; sum1=sum2=0; } } ans=ans*(((A(n,sum3+sum4+sum5,p)*jc_inv[sum3]%p)*jc_inv[sum4]%p)*jc_inv[sum5]%p)%p; cout<<ans<<endl; fclose(stdin); fclose(stdout); return 0; }
- 注意到
高爸
- 一个比较“显然”的结论:将最终的力量值设成原有的一条龙的力量值一定最优。
- 不会证明,咕了。
- 正解
-
三分
-
由
,需要离散化。 -
观察到,类似带权中位数,发现
通过一定的方案可以到达最小值,故为一个单谷函数,考虑三分。 -
设我们当前枚举到第
个位置,使 条龙的力量值为 ,有 。此时消耗的 点数为 。 -
类似 [ABC351F] Double Sum ,用权值树状数组维护
得到 ,然后进行计算即可。点击查看代码
ll x[100001],xx[100001],sum[100001],c[100001][2]; ll query(ll a[],ll x) { return lower_bound(a+1,a+1+a[0],x)-a; } ll lowbit(ll x) { return (x&(-x)); } void add(ll n,ll x,ll key,ll pd) { for(ll i=x;i<=n;i+=lowbit(i)) { c[i][pd]+=key; } } ll getsum(ll x,ll pd) { ll ans=0; for(ll i=x;i>=1;i-=lowbit(i)) { ans+=c[i][pd]; } return ans; } ll f(ll mid,ll a,ll b,ll i) { return (sum[i]-getsum(mid,1)-(i-getsum(mid,0))*xx[mid])*b+(getsum(mid,0)*xx[mid]-getsum(mid,1))*a; } bool check(ll mid1,ll mid2,ll a,ll b,ll i) { return f(mid1,a,b,i)>f(mid2,a,b,i); } int main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout); ll n,a,b,l,r,mid1,mid2,i; cin>>n>>a>>b; for(i=1;i<=n;i++) { cin>>x[i]; sum[i]=sum[i-1]+x[i]; xx[i]=x[i]; } sort(xx+1,xx+1+n); xx[0]=unique(xx+1,xx+1+n)-(xx+1); add(xx[0],query(xx,x[1]),1,0); add(xx[0],query(xx,x[1]),x[1],1); cout<<"0"<<endl; for(i=2;i<=n;i++) { add(xx[0],query(xx,x[i]),1,0); add(xx[0],query(xx,x[i]),x[i],1); l=1; r=xx[0]; while(l<=r) { mid1=l+(r-l)/3; mid2=r-(r-l)/3; if(check(mid1,mid2,a,b,i)==true) { l=mid1+1; } else { r=mid2-1; } } cout<<f(l,a,b,i)<<endl; } fclose(stdin); fclose(stdout); return 0; }
-
-
带权中位数
- 把权值
拆成分别有 个点。然后就转化为了 AcWing 104. 货仓选址 。
- 把权值
-
金牌
-
部分分
-
倍增求
,倍增优化跳父亲。- 把通过
和 的路径拆成三部分,分别是从 到 ,从 到 ,从 到 。 - 钦定
为根节点。 - 第一遍
时,设 表示以 为根的子树内的点到 的长度的价值之和,即 。 - 第二遍
时,进行换根。设 表示除原以 为根的子树内的点外的点到 的长度的价值之和。仍钦定 为根节点,状态转移方程为 。 - 然后进行分类讨论,求出
和 的 ,记为 。当 时,从乘法原理的角度分析,有 即为所求;当 中有一个等于 时,钦定 ,记 满足 在以 为根的子树内,从乘法原理的角度分析,有 即为所求。- 略带卡常。
点击查看代码
#define LOCAL namespace IO { #ifdef LOCAL FILE *Fin(fopen("d.in","r")),*Fout(fopen("d.out","w")); #else FILE *Fin(stdin),*Fout(stdout); #endif class qistream {static const size_t SIZE=1<<16,BLOCK=32;FILE*fp;char buf[SIZE];int p;public:qistream(FILE *_fp=stdin ):fp(_fp),p(0){fread(buf+p,1,SIZE-p,fp);}void flush(){memmove(buf,buf+p,SIZE-p),fread(buf+SIZE-p,1,p,fp),p=0;} qistream &operator>>(char &str){str = getch();while(isspace(str))str = getch();return*this;} template<class T>qistream &operator>>(T &x){x=0;p+BLOCK>=SIZE?flush():void();bool flag=false;for(;!isdigit(buf[p]);++p)flag=buf[p]=='-';for(;isdigit(buf[p]);++p)x=(x<<3)+(x<<1)+(buf[p]^48);x=flag?-x:x;return*this;}char getch(){return buf[p++];}qistream &operator>>(char*str){char ch=getch();while(ch<=' ')ch=getch();int i;for(i=0;ch>' '; ++i,ch=getch())str[i] = ch;str[i] = '\0';return*this;}}qcin(Fin); class qostream {static const size_t SIZE=1<<16,BLOCK=32;FILE*fp;char buf[SIZE];int p;public:qostream(FILE *_fp=stdout):fp(_fp),p(0){}~qostream(){fwrite(buf,1,p,fp);}void flush(){fwrite(buf,1,p,fp),p=0;}template<class T>qostream &operator<<(T x){int len=0;p+BLOCK>=SIZE?flush():void();x<0?(x=~x+1,buf[p++]='-'):0;do buf[p+len]=x%10+'0',x/=10,++len;while (x);for(int i=0,j=len-1;i<j;++i,--j)swap(buf[p+i],buf[p+j]);p+=len;return*this;}qostream&operator<<(char x){putch(x);return*this;}void putch(char ch){p+BLOCK>=SIZE?flush():void();buf[p++]=ch;}qostream &operator<<(char*str){for(int i=0;str[i];++i)putch(str[i]);return*this;}} qcout(Fout);}using namespace IO; #define cin qcin #define cout qcout const ll p=998244353; struct node { int nxt,to; }e[2000001]; int head[2000001],fa[2000001][25],N,cnt=0; ll dep[2000001],jc[2000001],f[2000001],g[2000001]; static inline void add(int u,int v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs(int x,int father) { fa[x][0]=father; dep[x]=dep[father]+1; f[x]=0; for(register int i=1;(1<<i)<=dep[x];++i) { fa[x][i]=fa[fa[x][i-1]][i-1]; } for(register int i=head[x];i;i=e[i].nxt) { if(e[i].to^father) { dfs(e[i].to,x); f[x]=(f[x]+((f[e[i].to]<<1)%p+2)%p)%p; } } } void reroot(int x,int father) { for(register int i=head[x];i;i=e[i].nxt) { if(e[i].to^father) { g[e[i].to]=(((g[x]<<1)%p+2)%p+(((f[x]-2*f[e[i].to]%p-2+p)%p)<<1)%p)%p; reroot(e[i].to,x); } } } static inline int lca(int x,int y) { if(dep[x]>dep[y]) { swap(x,y); } for(register int i=N;i>=0;--i) { if(dep[x]+(1<<i)<=dep[y]) { y=fa[y][i]; } } if(!(x^y)) { return x; } else { for(register int i=N;i>=0;--i) { if(fa[x][i]^fa[y][i]) { x=fa[x][i]; y=fa[y][i]; } } return fa[x][0]; } } int main() { freopen("d.in","r",stdin); freopen("d.out","w",stdout); register int n,m,u,v,rt,son,i,j; cin>>n; N=log2(n)+1; jc[0]=1; for(i=1;i<n;++i) { cin>>u>>v; add(u,v); add(v,u); jc[i]=(jc[i-1]<<1)%p; } jc[n]=(jc[n-1]<<1)%p; dfs(1,0); reroot(1,0); cin>>m; for(i=1;i<=m;++i) { cin>>u>>v; rt=lca(u,v); if((!(rt^u))||(!(rt^v))) { if(!(rt^v)) { swap(u,v); } son=v; for(j=N;j>=0;--j) { if(dep[fa[son][j]]>dep[u]) { son=fa[son][j]; } } cout<<(jc[dep[v]-dep[son]]*g[son]%p)*((f[v]+1)%p)%p<<endl; } else { cout<<(((f[u]+1)%p)*((f[v]+1)%p)%p)*jc[dep[u]+dep[v]-(dep[rt]<<1)]%p<<endl; } } fclose(stdin); fclose(stdout); return 0; }
- 把通过
-
求 ,倍增优化跳父亲。- 略带卡常。
点击查看代码
#define LOCAL namespace IO { #ifdef LOCAL FILE *Fin(fopen("d.in","r")),*Fout(fopen("d.out","w")); #else FILE *Fin(stdin),*Fout(stdout); #endif class qistream {static const size_t SIZE=1<<16,BLOCK=32;FILE*fp;char buf[SIZE];int p;public:qistream(FILE *_fp=stdin ):fp(_fp),p(0){fread(buf+p,1,SIZE-p,fp);}void flush(){memmove(buf,buf+p,SIZE-p),fread(buf+SIZE-p,1,p,fp),p=0;} qistream &operator>>(char &str){str = getch();while(isspace(str))str = getch();return*this;} template<class T>qistream &operator>>(T &x){x=0;p+BLOCK>=SIZE?flush():void();bool flag=false;for(;!isdigit(buf[p]);++p)flag=buf[p]=='-';for(;isdigit(buf[p]);++p)x=(x<<3)+(x<<1)+(buf[p]^48);x=flag?-x:x;return*this;}char getch(){return buf[p++];}qistream &operator>>(char*str){char ch=getch();while(ch<=' ')ch=getch();int i;for(i=0;ch>' '; ++i,ch=getch())str[i] = ch;str[i] = '\0';return*this;}}qcin(Fin); class qostream {static const size_t SIZE=1<<16,BLOCK=32;FILE*fp;char buf[SIZE];int p;public:qostream(FILE *_fp=stdout):fp(_fp),p(0){}~qostream(){fwrite(buf,1,p,fp);}void flush(){fwrite(buf,1,p,fp),p=0;}template<class T>qostream &operator<<(T x){int len=0;p+BLOCK>=SIZE?flush():void();x<0?(x=~x+1,buf[p++]='-'):0;do buf[p+len]=x%10+'0',x/=10,++len;while (x);for(int i=0,j=len-1;i<j;++i,--j)swap(buf[p+i],buf[p+j]);p+=len;return*this;}qostream&operator<<(char x){putch(x);return*this;}void putch(char ch){p+BLOCK>=SIZE?flush():void();buf[p++]=ch;}qostream &operator<<(char*str){for(int i=0;str[i];++i)putch(str[i]);return*this;}} qcout(Fout);}using namespace IO; #define cin qcin #define cout qcout const ll p=998244353; struct node { int nxt,to; }e[2000001]; int head[2000001],tarjan_f[2000001],u[2000001],v[2000001],vis[2000001],rt[2000001],dep[2000001],fa[2000001][25],cnt=0; ll jc[2000001],f[2000001],g[2000001]; vector<pair<int,int> >ask[2000001]; inline void add(rint u,rint v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs(rint x,rint father) { fa[x][0]=father; dep[x]=dep[father]+1; f[x]=0; for(rint i=1;(1<<i)<=dep[x];++i) { fa[x][i]=fa[fa[x][i-1]][i-1]; } for(rint i=head[x];i;i=e[i].nxt) { if(e[i].to^father) { dfs(e[i].to,x); f[x]=(f[x]+((f[e[i].to]<<1)%p+2)%p)%p; } } } void reroot(rint x,rint father) { for(rint i=head[x];i;i=e[i].nxt) { if(e[i].to^father) { g[e[i].to]=(((g[x]<<1)%p+2)%p+(((f[x]-2*f[e[i].to]%p-2+p)%p)<<1)%p)%p; reroot(e[i].to,x); } } } int find(rint x) { return ((tarjan_f[x]==x)?tarjan_f[x]:tarjan_f[x]=find(tarjan_f[x])); } void tarjan(rint x) { vis[x]=1; for(rint i=head[x];i;i=e[i].nxt) { if(vis[e[i].to]==0) { tarjan(e[i].to); tarjan_f[e[i].to]=x; } } for(rint i=0;i<ask[x].size();++i) { if(vis[ask[x][i].first]==2) { rt[ask[x][i].second]=find(ask[x][i].first); } } vis[x]=2; } int main() { freopen("d.in","r",stdin); freopen("d.out","w",stdout); rint n,m,uu,vv,son,i,j,N; cin>>n; N=log2(n)+1; jc[0]=1; for(i=1;i<n;++i) { cin>>uu>>vv; add(uu,vv); add(vv,uu); jc[i]=(jc[i-1]<<1)%p; tarjan_f[i]=i; } jc[n]=(jc[n-1]<<1)%p; tarjan_f[n]=n; dfs(1,0); reroot(1,0); cin>>m; for(i=1;i<=m;++i) { cin>>u[i]>>v[i]; if(u[i]==v[i]) { rt[i]=u[i]; } else { ask[u[i]].push_back(make_pair(v[i],i)); ask[v[i]].push_back(make_pair(u[i],i)); } } tarjan(1); for(i=1;i<=m;++i) { if((!(rt[i]^u[i]))||(!(rt[i]^v[i]))) { if(!(rt[i]^v[i])) { swap(u[i],v[i]); } son=v[i]; for(j=N;j>=0;--j) { if(dep[fa[son][j]]>dep[u[i]]) { son=fa[son][j]; } } cout<<(jc[dep[v[i]]-dep[son]]*g[son]%p)*((f[v[i]]+1)%p)%p<<endl; } else { cout<<(((f[u[i]]+1)%p)*((f[v[i]]+1)%p)%p)*jc[dep[u[i]]+dep[v[i]]-(dep[rt[i]]<<1)]%p<<endl; } } fclose(stdin); fclose(stdout); return 0; }
-
:树剖求 和 。-
略带卡常。
点击查看代码
#define LOCAL namespace IO { #ifdef LOCAL FILE *Fin(fopen("d.in","r")),*Fout(fopen("d.out","w")); #else FILE *Fin(stdin),*Fout(stdout); #endif class qistream {static const size_t SIZE=1<<16,BLOCK=32;FILE*fp;char buf[SIZE];ll p;public:qistream(FILE *_fp=stdin ):fp(_fp),p(0){fread(buf+p,1,SIZE-p,fp);}void flush(){memmove(buf,buf+p,SIZE-p),fread(buf+SIZE-p,1,p,fp),p=0;} qistream &operator>>(char &str){str = getch();while(isspace(str))str = getch();return*this;} template<class T>qistream &operator>>(T &x){x=0;p+BLOCK>=SIZE?flush():void();bool flag=false;for(;!isdigit(buf[p]);++p)flag=buf[p]=='-';for(;isdigit(buf[p]);++p)x=(x<<3)+(x<<1)+(buf[p]^48);x=flag?-x:x;return*this;}char getch(){return buf[p++];}qistream &operator>>(char*str){char ch=getch();while(ch<=' ')ch=getch();ll i;for(i=0;ch>' '; ++i,ch=getch())str[i] = ch;str[i] = '\0';return*this;}}qcin(Fin); class qostream {static const size_t SIZE=1<<16,BLOCK=32;FILE*fp;char buf[SIZE];ll p;public:qostream(FILE *_fp=stdout):fp(_fp),p(0){}~qostream(){fwrite(buf,1,p,fp);}void flush(){fwrite(buf,1,p,fp),p=0;}template<class T>qostream &operator<<(T x){ll len=0;p+BLOCK>=SIZE?flush():void();x<0?(x=~x+1,buf[p++]='-'):0;do buf[p+len]=x%10+'0',x/=10,++len;while (x);for(ll i=0,j=len-1;i<j;++i,--j)swap(buf[p+i],buf[p+j]);p+=len;return*this;}qostream&operator<<(char x){putch(x);return*this;}void putch(char ch){p+BLOCK>=SIZE?flush():void();buf[p++]=ch;}qostream &operator<<(char*str){for(ll i=0;str[i];++i)putch(str[i]);return*this;}} qcout(Fout);}using namespace IO; #define cin qcin #define cout qcout const ll p=998244353; struct node { int nxt,to; }e[2000010]; int head[2000010],siz[2000010],fa[2000010],dep[2000010],son[2000010],top[2000010],cnt=0; ll jc[2000010],f[2000010],g[2000010]; inline void add(rint u,rint v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs(rint x,rint father) { siz[x]=1; fa[x]=father; dep[x]=dep[father]+1; for(rint i=head[x];i;i=e[i].nxt) { if(e[i].to^father) { dfs(e[i].to,x); f[x]=(f[x]+((f[e[i].to]<<1)%p+2)%p)%p; siz[x]+=siz[e[i].to]; son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x]; } } } void reroot(rint x,rint father,rint id) { top[x]=id; if(son[x]) { g[son[x]]=(((g[x]<<1)%p+2)%p+(((f[x]-2*f[son[x]]%p-2+p)%p)<<1)%p)%p; reroot(son[x],x,id); for(rint i=head[x];i;i=e[i].nxt) { if(e[i].to^father&&e[i].to^son[x]) { g[e[i].to]=(((g[x]<<1)%p+2)%p+(((f[x]-2*f[e[i].to]%p-2+p)%p)<<1)%p)%p; reroot(e[i].to,x,e[i].to); } } } } inline int lca(rint u,rint v) { while(top[u]^top[v]) { if(dep[top[u]]>dep[top[v]]) { u=fa[top[u]]; } else { v=fa[top[v]]; } } return (dep[u]<dep[v])?u:v; } inline int dirson(rint u,rint v) { if(dep[u]>dep[v]) { swap(u,v); } while(top[u]^top[v]) { if(dep[top[u]]>dep[top[v]]) { if(!(fa[top[u]]^v)) { return top[u]; } u=fa[top[u]]; } else { if(!(fa[top[v]]^u)) { return top[v]; } v=fa[top[v]]; } } return (dep[u]<dep[v])?son[u]:son[v]; } int main() { rint n,m,u,v,rt,sonn,i; cin>>n; jc[0]=1; for(i=1;i<n;++i) { cin>>u>>v; add(u,v); add(v,u); jc[i]=(jc[i-1]<<1)%p; } jc[n]=(jc[n-1]<<1)%p; dfs(1,0); reroot(1,0,1); cin>>m; for(i=1;i<=m;++i) { cin>>u>>v; rt=lca(u,v); if((!(rt^u))||(!(rt^v))) { if(!(rt^v)) { swap(u,v); } sonn=dirson(u,v); cout<<(jc[dep[v]-dep[sonn]]*g[sonn]%p)*((f[v]+1)%p)%p<<endl; } else { cout<<(((f[u]+1)%p)*((f[v]+1)%p)%p)*jc[dep[u]+dep[v]-(dep[rt]<<1)]%p<<endl; } } return 0; }
-
-
正解
- 找
的过程等价于找 的 级祖先,可用长链剖分维护 luogu P5903 【模板】树上 K 级祖先 。 - 考虑在
的过程中维护一个栈,记录当前节点的所有祖先。可将询问离线下来放到节点上,当遍历到该节点时,它的 级祖先一定在当前栈内向下 个。 - 略带卡常,多交几发就过了。
点击查看代码
#define LOCAL namespace IO { #ifdef LOCAL FILE *Fin(fopen("d.in","r")),*Fout(fopen("d.out","w")); #else FILE *Fin(stdin),*Fout(stdout); #endif class qistream {static const size_t SIZE=1<<16,BLOCK=32;FILE*fp;char buf[SIZE];ll p;public:qistream(FILE *_fp=stdin ):fp(_fp),p(0){fread(buf+p,1,SIZE-p,fp);}void flush(){memmove(buf,buf+p,SIZE-p),fread(buf+SIZE-p,1,p,fp),p=0;} qistream &operator>>(char &str){str = getch();while(isspace(str))str = getch();return*this;} template<class T>qistream &operator>>(T &x){x=0;p+BLOCK>=SIZE?flush():void();bool flag=false;for(;!isdigit(buf[p]);++p)flag=buf[p]=='-';for(;isdigit(buf[p]);++p)x=(x<<3)+(x<<1)+(buf[p]^48);x=flag?-x:x;return*this;}char getch(){return buf[p++];}qistream &operator>>(char*str){char ch=getch();while(ch<=' ')ch=getch();ll i;for(i=0;ch>' '; ++i,ch=getch())str[i] = ch;str[i] = '\0';return*this;}}qcin(Fin); class qostream {static const size_t SIZE=1<<16,BLOCK=32;FILE*fp;char buf[SIZE];ll p;public:qostream(FILE *_fp=stdout):fp(_fp),p(0){}~qostream(){fwrite(buf,1,p,fp);}void flush(){fwrite(buf,1,p,fp),p=0;}template<class T>qostream &operator<<(T x){ll len=0;p+BLOCK>=SIZE?flush():void();x<0?(x=~x+1,buf[p++]='-'):0;do buf[p+len]=x%10+'0',x/=10,++len;while (x);for(ll i=0,j=len-1;i<j;++i,--j)swap(buf[p+i],buf[p+j]);p+=len;return*this;}qostream&operator<<(char x){putch(x);return*this;}void putch(char ch){p+BLOCK>=SIZE?flush():void();buf[p++]=ch;}qostream &operator<<(char*str){for(ll i=0;str[i];++i)putch(str[i]);return*this;}} qcout(Fout);}using namespace IO; #define cin qcin #define cout qcout const ll p=998244353; struct node { int nxt,to; }e[2000010]; int head[2000010],tarjan_f[2000010],u[2000010],v[2000010],k[2000010],kfa[2000010],vis[2000010],rt[2000010],dep[2000010],s[2000010],cnt=0,top=0; ll jc[2000010],f[2000010],g[2000010]; vector<pair<int,int> >ask_lca[2000010]; vector<int>ask_kfa[2000010]; inline void add(rint u,rint v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs(rint x,rint fa) { dep[x]=dep[fa]+1; for(rint i=head[x];i;i=e[i].nxt) { if(e[i].to^fa) { dfs(e[i].to,x); f[x]=(f[x]+((f[e[i].to]<<1)%p+2)%p)%p; } } } void reroot(rint x,rint fa) { top++; s[top]=x; for(rint i=0;i<ask_kfa[x].size();i++) { kfa[ask_kfa[x][i]]=s[top-k[ask_kfa[x][i]]]; } for(rint i=head[x];i;i=e[i].nxt) { if(e[i].to^fa) { g[e[i].to]=(((g[x]<<1)%p+2)%p+(((f[x]-2*f[e[i].to]%p-2+p)%p)<<1)%p)%p; reroot(e[i].to,x); } } top--; } int find(rint x) { return ((tarjan_f[x]==x)?tarjan_f[x]:tarjan_f[x]=find(tarjan_f[x])); } void tarjan(rint x) { vis[x]=1; for(rint i=head[x];i;i=e[i].nxt) { if(vis[e[i].to]==0) { tarjan(e[i].to); tarjan_f[e[i].to]=x; } } for(rint i=0;i<ask_lca[x].size();++i) { if(vis[ask_lca[x][i].first]==2) { rt[ask_lca[x][i].second]=find(ask_lca[x][i].first); } } vis[x]=2; } int main() { rint n,m,uu,vv,i,j; cin>>n; jc[0]=1; for(i=1;i<n;++i) { cin>>uu>>vv; add(uu,vv); add(vv,uu); jc[i]=(jc[i-1]<<1)%p; tarjan_f[i]=i; } jc[n]=(jc[n-1]<<1)%p; tarjan_f[n]=n; dfs(1,0); cin>>m; for(i=1;i<=m;++i) { cin>>u[i]>>v[i]; if(u[i]==v[i]) { rt[i]=u[i]; } else { ask_lca[u[i]].push_back(make_pair(v[i],i)); ask_lca[v[i]].push_back(make_pair(u[i],i)); } } tarjan(1); for(i=1;i<=m;++i) { if((!(rt[i]^u[i]))||(!(rt[i]^v[i]))) { if(!(rt[i]^v[i])) { swap(u[i],v[i]); } k[i]=dep[v[i]]-dep[u[i]]-1; ask_kfa[v[i]].push_back(i); } } reroot(1,0); for(i=1;i<=m;++i) { if((!(rt[i]^u[i]))||(!(rt[i]^v[i]))) { cout<<(jc[dep[v[i]]-dep[kfa[i]]]*g[kfa[i]]%p)*((f[v[i]]+1)%p)%p<<endl; } else { cout<<(((f[u[i]]+1)%p)*((f[v[i]]+1)%p)%p)*jc[dep[u[i]]+dep[v[i]]-(dep[rt[i]]<<1)]%p<<endl; } } return 0; }
- 找
总结
- 感觉这场比赛不是自己能力所能接受的,故写完
正解和 骗分,打到 就不打了。 - 要学会从身边各种事物中找到做题的灵感。
- 菜就多练。
后记
- 有大样例,好耶。
- @User-Unauthorized :这是我们考过最简单的一套题。
- @User-Unauthorized 给
各造了一个 的 数据点。 赛时时限 ,赛后改成了 。- @wkh2008 想挑战用倍增求
挑战 @User-Unauthorized 的数据,但他失败了。
- @wkh2008 想挑战用倍增求
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18003611,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具