2024初三年前集训测试2

2024初三年前集训测试2

\(T1\) 上海 \(100pts\)

  • 简化题意:给定一个正整数 \(k\) ,求最小的正整数 \(n\) 满足 \(k|n^{2},k \nmid n\) ,如无解则输出 -1

  • \(k=1\) 时,显然无解。

  • \(k \ne 1\) 时,由算术基本定理设 \(k=\prod\limits_{i=1}^{m}p_{i}^{c_{i}}\) ,容易得最小的正整数解 \(n\) 一定满足 \(n=\prod\limits_{i=1}^{m}p_{i}^{c_{i}'}\) ,其中 \(\sum\limits_{i=1}^{m}[c_{i}'<c_{i}] \ge 1,\sum\limits_{i=1}^{m}[c_{i} \le 2c_{i}']=m\) 。当 \(\sum\limits_{i=1}^{m}[c_{i}=1]=m\) 时,无解;否则构造 \(c_{i}'=\left\lceil \dfrac{c_{i}}{2} \right\rceil\) 即可,最终 \(n=\prod\limits_{i=1}^{m}p_{i}^{\left\lceil \frac{c_{i}}{2} \right\rceil}\) 即为所求。

    点击查看代码
    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;
    }
    

\(T2\) 华二 \(0pts\)

  • 部分分

    • \(10pts\) :因有 \(1 \le a_{i} \le 3\) ,令 \(num_{1},num_{2},num_{3}\) 分别表示 \(1,2,3\) 出现的次数。然后就转化成了多重集的排列数,全排列个数为 \(\dfrac{n!}{num_{1}!num_{2}!num_{3}!}\)
  • 正解

    • 注意到 \(1 \le a_{i} \le 9\) ,考虑利用这个性质。
    • 除了相等的数不能交换其余都是能够进行随便交换,交换两个相等的数等价于不交换,故一个数可以放到任何位置。
    • \(1,5,7\) 与其他任何数都互质,故可以放到任何位置,最后再进行处理。
    • \(2,3,4,6,8,9\) 中只有 \(6\) 与其他数都不互质,故两个 \(6\) 之间的数一定不能交换出去,等价于 \(6\) 的位置已经被固定了,设原来的数列就被 \(6\) 分成了 \(m\) 个区间。\(2,4,8\) 不能相互交换,相对位置(每两个数之间放其他的数的个数不固定)不变; \(3,9\) 不能相互交换,相对位置(每两个数之间放其他的数的个数不固定)不变。
    • 设第 \(i\) 个区间内 \(2,4,8\) 出现的次数为 \(sum_{i,1}\) ,第 \(i\) 个区间内 \(3,9\) 出现的次数为 \(sum_{i,2}\)\(num_{1},num_{2},num_{3}\) 分别表示 \(1,5,7\) 出现的次数。容斥后有 \(\dfrac{A_{num_{1}+num_{2}+num_{3}}^{num_{1}+num_{2}+num_{3}}}{A_{num_{1}}^{num_{1}}A_{num_{2}}^{num_{2}}A_{num_{3}}^{num_{3}}} \times \sum\limits_{i=1}^{m} \dbinom{sum_{i,1}+sum_{i,2}+1-1}{sum_{i,2}+1-1}\) 即为所求。
    点击查看代码
    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;
    }
    

\(T3\) 高爸 \(0pts\)

  • 一个比较“显然”的结论:将最终的力量值设成原有的一条龙的力量值一定最优。
    • 不会证明,咕了。
  • 正解
    • 三分

      • \(1 \le n \le 10^{5},1 \le x_{i} \le 10^9\) ,需要离散化。

      • 观察到,类似带权中位数,发现 \(mp\) 通过一定的方案可以到达最小值,故为一个单谷函数,考虑三分。

      • 设我们当前枚举到第 \(i\) 个位置,使 \(1 \sim i\) 条龙的力量值为 \(xx\) ,有 \(\sum\limits_{j=1}^{i}[x_{j}>xx]=p,\sum\limits_{j=1}^{i}[x_{j} \le xx]=i-p=q\) 。此时消耗的 \(mp\) 点数为 \(\begin{aligned}\sum\limits_{j=1}^{i}[x_{j}>xx] \times b(x_{j}-xx)+\sum\limits_{j=1}^{i}[x_{j} \le xx] \times a(xx-x_{j}) \\ =b(-p \times xx+\sum\limits_{j=1}^{i}[x_{j}>xx]x_{j})+a(q \times xx-\sum\limits_{j=1}^{i}[x_{j} \le xx]x_{j})\end{aligned}\)

      • 类似 [ABC351F] Double Sum ,用权值树状数组维护 \(q,\sum\limits_{j=1}^{i}[x_{j} \le xx]x_{j}\) 得到 \(p=i-q,\sum\limits_{j=1}^{i}[x_{j}>xx]x_{j}=\sum\limits_{j=1}^{i}x_{j}-\sum\limits_{j=1}^{i}[x_{j} \le xx]x_{j}\) ,然后进行计算即可。

        点击查看代码
        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;
        }
        
    • 带权中位数

\(T4\) 金牌 \(0pts\)

  • 部分分

    • \(69/99pts\)
      • 倍增求 \(LCA\) ,倍增优化跳父亲。

        • 把通过 \(x\)\(y\) 的路径拆成三部分,分别是从 \(l(l \in Subtree(x))\)\(x\) ,从 \(x\)\(y\) ,从 \(y\)\(r(r \in Subtree(y))\)
        • 钦定 \(1\) 为根节点。
        • 第一遍 \(DFS\) 时,设 \(f_{x}\) 表示以 \(x\) 为根的子树内的点到 \(i\) 的长度的价值之和,即 \(f_{x}=\sum\limits_{y \in Son(x)}(2f_{y}+2)\)
        • 第二遍 \(DFS\) 时,进行换根。设 \(g_{x}\) 表示除原以 \(x\) 为根的子树内的点外的点到 \(x\) 的长度的价值之和。仍钦定 \(1\) 为根节点,状态转移方程为 \(g_{x}=\begin{cases}0 & x=1 \\ 2g_{fa_{x}}+2+2(f_{fa_{x}}-2f_{x}-2) & x \ne 1\end{cases}\)
        • 然后进行分类讨论,求出 \(x\)\(y\)\(LCA\) ,记为 \(rt\) 。当 \(x \ne rt,y \ne rt\) 时,从乘法原理的角度分析,有 \((f_{x}+1)(f_{y}+1)2^{dis_{x,y}}\) 即为所求;当 \(x,y\) 中有一个等于 \(rt\) 时,钦定 \(x=rt\) ,记 \(son(son \in Son(x))\) 满足 \(y\) 在以 \(son\) 为根的子树内,从乘法原理的角度分析,有 \(g_{son}(f_{y}+1)2^{dis_{son,y}}\) 即为所求。
          • 略带卡常。
        点击查看代码
        #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;
        }   
        
      • \(Tarjan\)\(LCA\) ,倍增优化跳父亲。

        • 略带卡常。
        点击查看代码
        #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;
        }   
        
    • \(100pts\) :树剖求 \(LCA\)\(son\)
      • 略带卡常。

        点击查看代码
        #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;
        }   
        
  • 正解

    点击查看代码
    #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;
    }   
    

总结

  • 感觉这场比赛不是自己能力所能接受的,故写完 \(T1\) 正解和 \(T2,T3\) 骗分,打到 \(8:30\) 就不打了。
  • 要学会从身边各种事物中找到做题的灵感。
  • 菜就多练。

后记

  • 有大样例,好耶。
  • @User-Unauthorized :这是我们考过最简单的一套题。
  • @User-Unauthorized\(T4\) 各造了一个 \(1pts\)\(hack\) 数据点。
  • \(T4\) 赛时时限 \(1s\) ,赛后改成了 \(1.5s\)
posted @ 2024-02-02 17:55  hzoi_Shadow  阅读(48)  评论(3编辑  收藏  举报
扩大
缩小