zoukankan      html  css  js  c++  java
  • Codeforces #686 C

    前言

    手慢了,再给我10min就能 ak 了/dk

    C - Sequence Transformation

    题目大意

    给出一个数列,选择一个数使得这个数将这个数列划分成的段数最小。

    解题思路

    直接记录一个数上一次的出现位置,如果上个位置 (x) 与当前位置 (y) 的距离 (y-x>1) ,那么这个数划分成的段数就加一。

    Code

    const int N=2e5+5;
    int t,n,vis[N],sum[N],ok[N];
     
    signed main()
    {
    	t=read();
    	while(t--)
    	{
    		n=read();
    		for(int i=1;i<=n;++i)
    			vis[i]=0,sum[i]=0,ok[i]=0;
    		for(int i=1;i<=n;++i)
    		{
    			int a=read();
    			if(vis[a]!=i-1)
    				sum[a]++;
    			vis[a]=i;ok[a]=1;
    		}
    		for(int i=1;i<=n;++i)
    			if(vis[i]!=n)
    				sum[i]++;
    		int ans=1e18;
    		for(int i=1;i<=n;++i)
    			if(ok[i])
    				ans=min(ans,sum[i]);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    D - Number into Sequence

    题目大意

    构造一个数列使得这个数列每个数都大于 (1) 且乘积为 (n),后一个能整除前一个,使得这个数列最长。

    解题思路

    一个显然的想法是先把 (n) 质因数分解。

    因为分解的质因数都互质,所以如果要满足后一个能整除前一个,后一个就必须由前一个乘上一个质因子。

    但是如果数列中的好几个个数由好几个质因子们的乘积,那么不如把它们拆开成几个 质因子 和 一个质因子们的乘积。

    所以就相当于找出一个数量最多的质因子 (p) ,假如它的数量是 (q) ,那么数列的长度最长长度就是 (q),即 (q-1)(p) 和一个 (dfrac{n}{p^{q-1}})

    Code

    const int N=1e6+5;
    int t,n,m,k,a[N],b[N];
     
    struct Node
    {
    	int x,y;
    	bool operator < (const Node &p)const
    	{
    		return y>p.y;
    	}
     }c[N];
     
    signed main()
    {
    	t=read();
    	while(t--)
    	{
    		n=k=read();m=0;
    		for(int i=2;i*i<=n;++i)
    		{
    			if(n%i==0) a[++m]=i;
    			while(n%i==0){n/=i,++b[m];}
    		}
    		if(n>1)a[++m]=n,b[m]=1;
    		for(int i=1;i<=m;++i)
    			c[i]=(Node){a[i],b[i]};
    		sort(c+1,c+1+m);
    		int res=c[1].y;
    		printf("%lld
    ",res);
    		for(int i=1;i<=c[1].y-1;++i)
    			printf("%lld ",c[1].x),k/=c[1].x;
    		printf("%lld
    ",k);
    		for(int i=1;i<=m;++i)
    			a[i]=0,b[i]=0;
    	}
    	return 0;
    }
    

    E - Number of Simple Paths

    题目大意

    给一个环基树,问有多少条长度大于 (1) 的简单路径。

    解题思路

    显然如果两个点在环基树中的同一个树中,那么他们之间只存在 (1) 条简单路径。

    如果两个点在环基树的不同树中或有一个在环上,那么他们之间存在 (2) 条简单路径(从环的一半边走或从环的另一半边走)。

    所以可以先拓扑排序找出环,然后统计出环基树中每棵树的大小。

    显然一棵树对答案的贡献就是 树的大小 ( imes) (() 每个点与树内点的路径数 (+) 每个点与树外点的路径数 ())

    设这可数的大小为 (siz)(siz imes ((siz-1) + (n-siz) imes2))

    Code

    const int N=2e5+5;
    int t,n,vis[N],on[N],col[N],siz[N],du[N],ans,flag;
     
    struct Edge
    {
    	int v,ne;
    }e[N*2];
    int head[N],tot;
     
    inline void add(int u,int v);
    void dfs(int u,int fa,int c);
     
    queue<int> qu;
     
    signed main()
    {
    	t=read();
    	while(t--)
    	{
    		n=read();ans=0;
    		for(int i=1;i<=n;++i)
    		{
    			int u=read(),v=read();
    			add(u,v);add(v,u);du[u]++,du[v]++;
    		}
    		while(!qu.empty()) qu.pop();
    		for(int i=1;i<=n;++i)
    			if(du[i]==1) qu.push(i);
    		while(!qu.empty())
    		{
    			int u=qu.front();
    			qu.pop();
    			on[u]=1;
    			for(int i=head[u];i;i=e[i].ne)
    			{
    				int v=e[i].v;
    				du[v]--;
    				if(du[v]==1) qu.push(v);
    			}
    		}
    		int m=0;
    		for(int i=1;i<=n;++i)
    			if(on[i]==0) dfs(i,0,++m);
    		ans=0;
    		for(int i=1;i<=m;++i)
    			ans+=siz[i]*(siz[i]-1+(n-siz[i])*2);
    		printf("%lld
    ",ans/2);
    		for(int i=1;i<=n;++i)
    		{
    			head[i]=0;du[i]=0;
    			vis[i]=0;on[i]=0;
    			col[i]=0;siz[i]=0;
    		}
    		tot=0;flag=0;
    	}
    	return 0;
    }
     
    inline void add(int u,int v)
    {
    	e[++tot]=(Edge){v,head[u]};
    	head[u]=tot;
    }
     
    void dfs(int u,int fa,int c)
    {
    	col[u]=c;
    	siz[c]++;
    	for(int i=head[u];i;i=e[i].ne)
    	{
    		int v=e[i].v;
    		if(v==fa||on[v]==0)
    			continue;
    		dfs(v,u,c);
    	}
    }
    

    F - Array Partition

    题目大意

    把一个数列划分成三段,使得 第一段的 (max=) 第二段的 (min=) 第三段的 (max)

    解题思路

    我们假设第一段和第二段的分解点是 (x),第二段和第三段的分解点是 (y)

    我们可以枚举第一段和第二段的分界点 (x) ,这样就知道了要使第二段的 (min) 和第三段的 (max) 要等于的值。

    可以先考虑如何让第二段的 (min) 与 第一段的 (max) 相等。

    由于第二段区间 ([x,y])(min) 一定是单调不升的,所以可以二分这个位置,这样就能在找到一个区间 ([p,q]) ,在这个区间选第二段和第三段的分界点,就能保证第二段的 (min) 与 第一段的 (max) 相等。

    再考虑如何保证第三段的 (min) 与 第一段的 (max) 相等。

    其实刚才求出的区间 ([p,q])(max) 也是单调不降的,所以依旧可以二分。

    如果能找到,那么直接输出这个方案就行了。

    二分的时候要维护区间极值,可以直接套一个 st表 或 线段树。

    时间复杂度 ( ext{O}(n log^2n))

    Code

    const int N=2e5+5;
    int t,n,a[N],val[N*4],suc[N],flag;
     
    void build(int x,int l,int r);
    int query(int x,int l,int r,int L,int R);
    inline int binary1(int x,int p);
    inline int binary2(int x,int l,int r);
     
    signed main()
    {
    	t=read();
    	while(t--)
    	{
    		n=read();
    		for(int i=1;i<=n;++i)
    			a[i]=read();
    		build(1,1,n);
    		for(int i=n;i>=1;--i)
    			suc[i]=max(suc[i+1],a[i]);
    		int now=0;flag=0;
    		for(int i=1;i<=n;++i)
    		{
    			now=max(now,a[i]);
    			int pos1=binary1(now,i+1)+1;
    			int pos2=binary1(now+1,i+1)+2;
    			if(pos1==-1) continue;
    			if(pos2==0) pos2=i+2;
    			if(pos1>n) pos1=n; 
    			if(pos2>n) pos2=n;
    			int pos3=binary2(now,pos2,pos1);
    			if(pos3==-1) continue;
    			if(i<=0||pos3-1-i<=0||n-(pos3-1-i)-i<=0) continue;
    			if(suc[pos3]!=now||query(1,1,n,i+1,pos3-1)!=now)
    				continue;
    			printf("YES
    %lld %lld %lld
    ",i,pos3-1-i,n-(pos3-1-i)-i);
    			flag=1;break;
    		}
    		if(flag==0) printf("NO
    ");
    		for(int i=1;i<=n;++i)
    			suc[i]=0;
    	}
    	return 0;
    }
     
    void build(int x,int l,int r)
    {
    	if(l==r)
    	{
    		val[x]=a[l];
    		return;
    	}
    	build(lc,l,mid);
    	build(rc,mid+1,r);
    	val[x]=min(val[lc],val[rc]);
    }
     
    int query(int x,int l,int r,int L,int R)
    {
    	if(L<=l&&r<=R) return val[x];
    	int res=1e18;
    	if(L<=mid) res=min(res,query(lc,l,mid,L,R));
    	if(mid+1<=R) res=min(res,query(rc,mid+1,r,L,R));
    	return res;
    }
     
    inline int binary1(int x,int p)
    {
    	int l=p,r=n,res=-2;
    	while(l<=r)
    	{
    		if(query(1,1,n,p,mid)>=x)
    		{
    			res=mid;
    			l=mid+1;
    		}
    		else r=mid-1;
    	}
    	return res;
    }
     
    inline int binary2(int x,int l,int r)
    {
    	int res=-1;
    	while(l<=r)
    	{
    		if(suc[mid]<=x)
    		{
    			res=mid;
    			r=mid-1;
    		}
    		else l=mid+1;
    	}
    	return res;
    }
    
  • 相关阅读:
    [转载]WSUS客户端排错--使用wsus client tools
    [转载]vSphere ESXi主机配置iSCSI存储
    RHEL6.5下oracle11G的监听启动停止
    配置EM遇到的问题:*_orcl not foundlistener not upError creating the repository
    chrome有道翻译--书签栏关闭开启快捷键
    linux下sqlplus实现浏览历史命令和删除错误字母功能
    windows下plsql安装并配置oracle client
    chrome google浏览器添加AdBlock插件
    Python基础之异常处理
    Python基础之finally异常处理
  • 原文地址:https://www.cnblogs.com/blackbird137/p/14035456.html
Copyright © 2011-2022 走看看