zoukankan      html  css  js  c++  java
  • 杭二集训 2019.8.16

    T1

    题目意思:给定一个01串,你可以进行区间异或操作,最少用几次能让这个串完全相同

    数据范围:(nle 1e7)

    Solution:

    (f[i])表示全变成1的最小操作数,(g[i])表示全变成0,输出min值

    Code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e7+1;
    int n,f[N],g[N];char s[N];
    int main(){
    	scanf("%s",s+1);n=strlen(s+1);
    	s[1]=='0'?f[1]=1:g[1]=1;
    	for(int i=2;i<=n;i++){
    		f[i]=f[i-1],g[i]=g[i-1];
    		if(s[i]!=s[i-1])
    			s[i]=='0'?f[i]++:g[i]++;
    		f[i]=min(f[i],g[i]+1);
    		g[i]=min(g[i],f[i]+1);
    	}return printf("%d
    ",min(f[n],g[n])),0;
    }
    
    

    T2

    题目意思:给定长度为(n)的一个数列,求(sum_{i=1}^nsum_{j=1}^n lcm(a_i,a_j))

    数据范围:(nle1e6,a_ile1e6)

    Solution:

    [sum_{i=1}^nsum_{j=1}^n{a_i imes a_j over gcd(a_i,a_j)}\ d=gcd(a_i,a_j)\ sum_{i=1}^nsum_{j=1}^n{a_i imes a_j over d}\ M=max \,a_i\ sum_{d=1}^M sum_{d|a_i}sum_{d|a_j}[gcd({a_i over d},{a_j over d})=1] a_i imes a_j \ D=gcd({a_i over d},{a_j over d})\ sum_{d=1}^M sum_{d|a_i}sum_{d|a_j} sum_{t|D} mu(t) a_i imes a_j\ ]

    [sum_{d=1}^M sum_{t=1}^M mu(t)sum_{d|a_i}sum_{d|a_j}sum_{t|{a_i over d}}sum_{t|{a_jover d}} {a_i imes a_j over d}\ sum_{d=1}^M sum_{t=1}^M mu(t)sum_{d imes t|a_i}sum_{d imes t|a_j}{a_i imes a_j over d}\T=a_i imes a_j\ sum_{T=1}^Msum_{t|T} mu(t) tsum_{T|a_i}sum_{T|a_j} {a_i imes a_j over T}\ ]

    推式子就到此为止了(并没有),考虑如何预处理出后面的两个式子,设(v_i)表示(i)的出现次数

    [sum_{T|a_i}sum_{T|a_j}{a_i imes a_j over T}\ T(sum_{k=1}^M v_{kT} imes k)^2\ ]

    于是后面的式子可以做到(O(n \, log \, n))预处理,前一个式子则在线筛中处理

    Code:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=1e6+1;
    const int p=998244353;
    int M,n,a[N],mu[N],v[N];
    int tot,pri[N],vis[N];
    long long ans,tmp,f[N],g[N],sum[N];
    void prepare(){mu[1]=1;f[1]=1;
    	for(int i=2;i<=M;i++){
    		if(!vis[i]) pri[++tot]=i,mu[i]=-1,f[i]=1-i;
    		for(int j=1;j<=tot&&i*pri[j]<=M;j++){
    			vis[i*pri[j]]=1;
    			if(i%pri[j]==0){
    				int w=pri[j],x=i,u=w;
    				while(x%w==0){x/=w;u*=w;}
    				if(x==1) f[u*x]=(f[u/w]+(mu[u]*1ll*u)%p)%p;
    				else f[u*x]=(f[u]*1ll*f[x])%p;
    				break;
    			}
    			f[i*pri[j]]=f[i]*1ll*f[pri[j]];
    			f[i*pri[j]]%=p;mu[i*pri[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=M;i++){
    		long long re=0;
    		for(int j=1;j<=M/i;j++)
    			re+=j*1ll*v[i*j],re%=p;
    		g[i]=i*((re*1ll*re)%p);
    	}
    }
    int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    	return x*f;
    }
    int gcd(int x,int y){
    	return !y?x:gcd(y,x%y);
    }
    long long lcm(int x,int y){
    	long long re=x*1ll*y;
    	return re/gcd(x,y);
    }
    signed main(){
    	n=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read(),v[a[i]]++,M=max(M,a[i]);
    	prepare();
    	for(int i=1;i<=M;i++){
    		ans+=f[i]*1ll*g[i],ans%=p;
    		ans=(ans+p)%p;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    

    T3

    题目意思:给你一棵n个点n-1条边的树,每个点i上有一个可正可负的整数权值ai。我们定义树上一个连通块的权值为其中所有点的权值和。有q次询问,每次询问给出k个点(保证包含1号点),请你告诉他所有包含这k个点的联通块中,权值最大的连通块权值是多少

    Solution:

    (f[x])表示(x)的子树内,包含(x)点的最大连通块权值和

    那么每次询问的答案可以表示为:(f[1]+sum_{iin V}[f[i]<0]\,\,f[i])

    其中集合(V)表示这(k)个点构成联通块所需的最少的点的点集

    这个其实很好理解,考虑(f[x])的转移:(f[x]=sum_{iin son_x} [f[i]>0]\,\,f[i])

    也就是说,对于所有(f[x]>0)的点来说,他们的贡献都是加入到了答案里的

    那么我们只需要考虑如何快速的算出上面的式子就行了

    考虑(g[x])(g[x]=sum_{vin up_x} [f[v]<0]\,\,f[v]),其中(up_x)表示从(x)到根节点需要经过的所有点的集合(包过(x),不包过根)

    那么我们只需要用set维护dfs序,再求lca维护(g)值就OK了(维护参考异象石)

    Code:

    #include<bits/stdc++.h>
    #define IT set<int,Pos>:: iterator
    using namespace std;
    const int N=1e5+1;
    int n,q,cnt,tim,head[N];
    int dep[N],a[N],p[22][N],dfn[N];
    long long f[N],g[N];
    struct Edge{int nxt,to;}edge[N<<1];
    struct Pos{
    	bool operator () (int a,int b){return dfn[a]<dfn[b];}
    };set<int,Pos> s;
    void ins(int x,int y){
    	edge[++cnt].nxt=head[x];
    	edge[cnt].to=y;head[x]=cnt;
    }
    void dfs1(int x,int fa){
    	dfn[x]=++tim;
    	dep[x]=dep[fa]+1;p[0][x]=fa;
    	for(int i=head[x];i;i=edge[i].nxt){
    		int y=edge[i].to;
    		if(y==fa) continue;
    		dfs1(y,x);if(f[y]>0) f[x]+=f[y];
    	}f[x]+=a[x];
    }
    void trans(){
    	for(int i=1;i<=log2(n)+1;i++)
    		for(int j=1;j<=n;j++)
    			p[i][j]=p[i-1][p[i-1][j]];
    }
    int lca(int x,int y){
    	if(x==1||x==y) return x;
    	if(dep[x]<dep[y]) swap(x,y);
    	for(int i=log2(n)+1;i>=0;i--)
    		if(dep[p[i][x]]>=dep[y]) x=p[i][x];
    	if(x==y) return x;
    	for(int i=log2(n)+1;i>=0;i--)
    		if(p[i][x]!=p[i][y]) x=p[i][x],y=p[i][y];
    	return p[0][x];
    }
    void dfs2(int x,int fa){
    	g[x]=g[fa];if(f[x]<0) g[x]+=f[x];
    	for(int i=head[x];i;i=edge[i].nxt){
    		int y=edge[i].to;
    		if(y==fa) continue;
    		dfs2(y,x);
    	}
    }
    int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    	return x*f;
    }
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	for(int i=1;i<n;i++){
    		int x=read(),y=read();
    		ins(x,y),ins(y,x);
    	}
    	dfs1(1,0);trans();dfs2(1,0);
    	q=read();
    	for(int i=1;i<=q;i++){
    		int k=read();s.clear();
    		for(int j=1;j<=k;j++){
    			int x=read();
    			s.insert(x);
    		}
    		IT it=s.begin();int lst=*it;
    		long long ans=0;
    		while(it!=s.end()){++it;
    			if(it==s.end()){
    				ans+=g[lst];
    				break;
    			}int x=*it;
    			ans+=g[x]+g[lst]-2*g[lca(x,lst)];
    			lst=x;
    		}printf("%lld
    ",(ans/2)+f[1]);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    制作Autorun的CD
    Sybase ASE MDA tables 装不上怎么办?
    对于TStringList.Find函数,我有话要说
    HH.exe CHM Operator Command.
    Delphi 7的一些常用的快捷键
    Explain Plan
    在Delphi中的Log
    subst windows下实用的磁盘映射工具
    Excel 2007 如何冻结多行&多列
    LinqToDataTable[转]
  • 原文地址:https://www.cnblogs.com/NLDQY/p/11374321.html
Copyright © 2011-2022 走看看