zoukankan      html  css  js  c++  java
  • NOIP2020模拟赛(二十五)7.26 结题报告

    A.求和

    A.求和
    大致意思就是求

    [sum_{i=1}^{n} sum_{j=1}^{m} lbrack i eq j brack(n ; mod; i)(m ; mod ; j) ]

    solve

    这题我们要从模的本质出发:

    [a quad mod quad b = a - b imes lfloor frac{a}{b} floor ]

    我们首先不考虑(i eq j)条件,单独对(i)(j)讨论,我们可以得到

    [sum_{i = 1}^{n}n quad mod quad i=sum_{i = 1}^{n}n-i imes lfloor frac{n}{i} floor ]

    化简一下,可以得到

    [sum_{i = 1}^{n}n-i imes lfloor frac{n}{i} floor = n^{2}-sum_{i=1}^{n}i lfloor frac{n}{i} floor ]

    由与(lfloor frac{n}{i} floor)不同的只有(sqrt{n})个,这个式子可以(O(sqrt{n}))计算。对于(i),(j)分别做一遍相乘起来即可。

    对于(i=j)的部分,单独拿出来减去贡献即可。我们用类似的方法,即求

    [sum_{i=1}^{min(n,m)}(nquad modquad i)(mquad modquad i) ]

    然后跟之前一样的处理方法化为求

    [sum_{i=1}^{min(n,m)}(n-i imes lfloor frac{n}{i} floor)(m - i imes lfloor frac{m}{i} floor) ]

    稍微化简一下就可以也(sqrt{n})分块了

    [sum_{i=1}^{min(n,m)}(nm - mi lfloor frac{n}{i} floor - ni lfloor frac{m}{i} floor + i^{2}lfloor frac{m}{i} floor lfloor frac{n}{i} floor) ]

    最后相减就好了

    code

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define MO 19940417
    #define si 3323403
    using namespace std;
    ll n,m,Sn,Sm,S3,Ans;
    ll Mod(ll x){
    	if (x<0) return x+MO;
    	if (x>=MO) return x-MO;
    	return x;
    }
    int main(){
    	scanf("%lld%lld",&n,&m);
    	if (n>m) swap(n,m);
    	Sn=n*n%MO;Sm=m*m%MO;S3=Sn*m%MO;
    	for (ll i=1,j;i<=n;i=j+1){
    		j=min(n,n/(n/i));
    		Sn=Mod(Sn-(n/i)*((i+j)*(j-i+1)/2%MO)%MO);
    	}
    	for (ll i=1,j;i<=m;i=j+1){
    		j=min(m,m/(m/i));
    		Sm=Mod(Sm-(m/i)*((i+j)*(j-i+1)/2%MO)%MO);
    	}
    	
    	for (ll i=1,j;i<=n;i=j+1){
    		j=min(n,min(n/(n/i),m/(m/i)));
    		S3=Mod(S3-(m/i*n+n/i*m)%MO*((i+j)*(j-i+1)/2%MO)%MO+(n/i)*(m/i)%MO*Mod(j*(j+1)%MO*(2*j+1)%MO-(i-1)*i%MO*(2*i-1)%MO)%MO*si%MO);
    	}
    	printf("%lld
    ",Mod(Sn*Sm%MO-S3));
    	return 0;
    }
    

    B.排队

    B.排队

    solve

    看到这道题,第一反应就是这个关系是一棵树

    对于每一个节点的不同儿子,先后顺序有着很大的影响,为了消除这种影响,我们先进行一道转化,先可以把比 (x_i) 级别小的所有节点都插入到 (x_i) 的子树中,这样就方便统计了。

    如果一个结点有两个儿子l,r,并且l排在r的前面,那么总的方法数就是(f[l]*f[r]*C(size[l]+size[r],size[l]-1))

    其含义是:容易想到,根据乘法原理,总共会有(f[l]*f[r])种情况,对于每种情况,都可以有(C(size[l]+size[r],size[l]-1))种合并方法

    子树总共有(size[l]+size[r])个结点(不算根结点),所以空的位置就是(size[l]+size[r])个,其中属于(l)的总共就有(size[l]-1)个,这个就直接用组合数就算出来了

    然后再一个个往后合并就好了

    code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int TT=10007;
    const int maxn=1005,maxe=2005;
    int N,lnk[maxn],nxt[maxe],son[maxe],cnt,size[maxn],F[maxn],T,C[maxn<<1][maxn<<1],lst;
    inline int read(){
    	int ret=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
    	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
    	return ret*f;
    }
    inline void add_e(int x,int y){son[++cnt]=y;nxt[cnt]=lnk[x];lnk[x]=cnt;}
    void DFS(int x){
    	size[x]=1;F[x]=1;
    	for(int j=lnk[x];j;j=nxt[j]){
    		DFS(son[j]);
    		size[x]+=size[son[j]];
    		F[x]=F[x]*(F[son[j]])%TT;
    		if(j!=lnk[x])F[x]=(F[x]*C[size[x]-1][size[son[j]]])%TT;
    	}
    	return ;
    }
    int main(){
    //	freopen("c.in","r",stdin);
    //	freopen("c.out","w",stdout);
    	T=read();
    	C[0][0]=1;
    	for(int i=1;i<=2000;i++)
    	for(int j=0;j<=2000;j++)C[i][j]=i==j||j==0?1:(C[i-1][j]+C[i-1][j-1])%TT;
    	while(T--){
    		cnt=0;
    		memset(F,0,sizeof F);
    		memset(lnk,0,sizeof lnk);
    		memset(nxt,0,sizeof nxt);
    		memset(son,0,sizeof son);
    		memset(size,0,sizeof size);
    		N=read();
    		for(int i=1;i<=N;i++){
    			int p=read();lst=i;
    			for(int j=1;j<=p;j++){
    				int x=read();
    				add_e(lst,x);lst=x;
    			}
    		}
    		DFS(1);
    		printf("%d
    ",F[1]);
    	}
    	return 0;
    }
    

    C.城市

    C.城市

    solve

    仔细读这道题,我们发现就是找一个环上点的最大值最小值。

    显然,贪心的想法,我们先建一颗最小生成树,然后我们再加一条边就变成一个环了,我们加边也由小到大来加

    每加一条边,我们就要将边所对应的的两个点在树上的路径赋成这条边的权值,但是这样显然是超时的,要考虑怎么优化。

    我们可以用并查集来链接,这样就能保证每条边的遍历次数大大减小

    对于询问,每两个点之间的最大权值,我们用LCA来维护,当我们查询时发现x和y不连通,即是无解。

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    const int maxn=100005,maxe=500005;
    int n,m,q,w[maxn],lgn;struct Y{int x,y,z;}e[maxe];
    int fa[maxn],pa[maxn][20],dep[maxn],f[maxn][20];
    int son[maxn<<1],lnk[maxn],lst[maxn<<1],tot;bool vis[maxe];
    inline int red(){
    	int ret=0;char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)) ret=(ret<<3)+(ret<<1)+(ch^48),ch=getchar();
    	return ret;
    }
    inline int abs_(int x){return x>0? x:-x;}
    inline bool cmp(Y x,Y y){return x.z<y.z;}
    inline int max_(int x,int y){return x>y? x:y;}
    int gt(int x){return x==fa[x]? x:fa[x]=gt(fa[x]);}
    inline int lg(int x){int r=-1;while(x) r++,x>>=1;return r;}
    inline void e_(int x,int y){son[++tot]=y;lst[tot]=lnk[x];lnk[x]=tot;}
    void DFS(int x){
    	for(int j=lnk[x];j;j=lst[j]) if(son[j]!=pa[x][0])
    	 dep[son[j]]=dep[x]+1,pa[son[j]][0]=x,DFS(son[j]);
    }
    inline int LCA(int x,int y){
    	int ret=0;
    	if(dep[x]<dep[y]) x^=y^=x^=y;
    	for(int i=lgn;~i;i--){
    		if(dep[pa[x][i]]>=dep[y])
    		 ret=max_(ret,f[x][i]),x=pa[x][i];
    		if(x==y) return ret;
    	}
    	for(int i=lgn;~i;i--) if(pa[x][i]!=pa[y][i])
    	 ret=max_(ret,max_(f[x][i],f[y][i])),x=pa[x][i],y=pa[y][i];
    	return max_(ret,max_(f[x][0],f[y][0]));
    }
    int main(){
    	n=red(),m=red(),q=red();lgn=lg(n);
    	for(int i=1;i<=n;i++) w[fa[i]=i]=red();
    	for(int i=1,x,y;i<=m;i++){
    		x=red(),y=red();
    		e[i]=(Y){x,y,abs_(w[x]-w[y])};
    	}
    	std::sort(e+1,e+1+m,cmp);
    	for(int i=1,fx,fy;i<=m;i++){
    		fx=gt(e[i].x);fy=gt(e[i].y);
    		if(fx==fy){vis[i]=1;continue;}
    		fa[fx]=fy;e_(e[i].x,e[i].y);e_(e[i].y,e[i].x);
    	}
    	DFS(1);
    	for(int i=1;i<=n;i++) fa[i]=i;
    	for(int i=1,x,y;i<=m;i++) if(vis[i]){
    		x=gt(e[i].x),y=gt(e[i].y);
    		while(x!=y){
    			if(dep[x]<dep[y]) x^=y^=x^=y;
    			f[x][0]=e[i].z;x=fa[x]=gt(pa[x][0]);
    		}
    	}
    	for(int j=1;j<=lgn;j++) for(int i=1;i<=n;i++)
    	 pa[i][j]=pa[pa[i][j-1]][j-1],f[i][j]=max_(f[i][j-1],f[pa[i][j-1]][j-1]);
    	for(int x,y;q--;){
    		x=red();y=red();
    		if(gt(x)!=gt(y)) printf("infinitely
    ");
    		else printf("%d
    ",LCA(x,y));
    	}
    	return 0;
    }
    
  • 相关阅读:
    四、Signalr手持令牌验证
    三、Signalr外部链接
    三、使用Fiddler劫持网络资源(手机端)
    一、数据库层搭建
    学会聊天
    weblogic实时监控开发
    jrockit静默安装笔记
    自动磁盘分区脚本
    WebsphereMQ搭建集群
    Websphere MQ Cluster
  • 原文地址:https://www.cnblogs.com/martian148/p/13384324.html
Copyright © 2011-2022 走看看