Codeforces Round #686 (Div. 3)

比赛链接

Codeforces Round #686 (Div. 3)

F. Array Partition

判断是否能将一个长度为 \(n\) 的数组分成 \(3\) 部分,使得两边的最大值都等于中间的最小值

解题思路

st,二分,前缀最值

可以先处理前缀最值和后缀最值,用后缀最值遍历后部分,中间部分用 \(st\) 表维护最小值,将前部分和中间部分满足条件的区间二分出来再判断即可

  • 时间复杂度:\(O(nlogn)\)

代码

// Problem: F. Array Partition
// Contest: Codeforces - Codeforces Round #686 (Div. 3)
// URL: https://codeforces.com/contest/1454/problem/F
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=2e5+5;
int t,n,a[N],f[N][20],mx[N],mx1[N];
int ask(int l,int r)
{
    int k=log(r-l+1)/log(2);
    return min(f[l][k],f[r-(1<<k)+1][k]);
}
signed main()
{
	help;
	memset(f,0x3f,sizeof f);
	for(cin>>t;t;t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)cin>>a[i],f[i][0]=a[i],mx[i]=max(a[i],mx[i-1]);
		for(int i=n;i>=1;i--)mx1[i]=max(mx1[i+1],a[i]);
		int c=log(n)/log(2);
		for(int j=1;j<=c;j++)
	        for(int i=1;i+(1<<(j-1))<=n;i++)
	            f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
	    bool fl=false;
	    int x,y,z;
	    for(int i=n;i-2>=1;i--)
	    {
	    	z=n-i+1;
	    	int rpos=upper_bound(mx+1,mx+i-2+1,mx1[i])-mx-1;
	    	int lpos=lower_bound(mx+1,mx+i-2+1,mx1[i])-mx;
	    	if(lpos<i-1&&mx[lpos]==mx1[i])
	    	{
	    		int l=2,r=i-1;
	    		while(l<r)
	    		{
	    			int mid=l+r+1>>1;
	    			if(ask(mid,i-1)<=mx1[i])l=mid;
	    			else
	    				r=mid-1;
	    		}
	    		if(l>=2&&l<=i-1&&ask(l,i-1)==mx1[i])
	    		{
	    			int posr=l;
	    			int l=2,r=i-1;
		    		while(l<r)
		    		{
		    			int mid=l+r>>1;
		    			if(ask(mid,i-1)>=mx1[i])r=mid;
		    			else
		    				l=mid+1;
		    		}
		    		int posl=l;
		    		if(rpos+1==posl)
		    		{
		    			x=rpos,y=n-x-z;
	    				fl=true;
    					break;
		    		}
		    		int ll=max(posl,lpos),rr=min(posr,rpos);
		    		if(ll<=rr)
		    		{
		    			if(ll-1>=lpos)
		    			{
		    				x=ll-1,y=n-x-z;
		    				fl=true;
	    					break;
		    			}
		    			if(rr+1<=posr||rr-ll+1>=2)
		    			{
		    				x=ll,y=n-x-z;
		    				fl=true;
	    					break;
		    			}
		    		}
	    		}
	    	}
	    }
	    if(fl)
	    {
	    	puts("YES");
	    	cout<<x<<' '<<y<<' '<<z<<'\n';
	    }
	    else
	    	puts("NO");
	    for(int i=1;i<=n;i++)
	    	mx[i]=mx1[i]=0;
	    for(int j=1;j<=c;j++)
	        for(int i=1;i<=n;i++)
	        	f[i][j]=f[i][0]=0x3f3f3f3f;
	}
	return 0;
}

E. Number of Simple Paths

求一棵基环树的简单路径的数量

解题思路

容斥原理

假设所有点对之间都有两条路径,则数量为 \(n\times (n-1)\),利用容斥原理,减去只有一条路径的点对数量即可,即对于基环上的点,设其子树大小为 \(sz\),子树上的任意两点都只有一条路径,其数量为 \(sz\times (sz-1)/2\),求环上的点可以利用拓扑排序不断将所有度数为 \(1\) 的清除掉,剩下的点即为环上的点// Problem: E. Number of Simple Paths
// Contest: Codeforces - Codeforces Round #686 (Div. 3)
// URL: https://codeforces.com/contest/1454/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq

include <bits/stdc++.h>

//#define int long long

define help

define pb push_back

define fi first

define se second

define mkp make_pair

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;

template bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }

template void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}

const int N=2e5+5;
int t,n,de[N],sz[N];
bool v[N];
vector adj[N];
int dfs(int x,int fa)
{
sz[x]=1;
for(int y:adj[x])
{
if(!v[y]||yfa)continue;
dfs(y,x);
sz[x]+=sz[y];
}
return sz[x];
}
int main()
{
for(cin>>t;t;t--)
{
cin>>n;
for(int i=1;i<=n;i++)adj[i].clear(),de[i]=v[i]=sz[i]=0;
for(int i=1;i<=n;i++)
{
int x,y;
cin>>x>>y;
adj[x].pb(y),adj[y].pb(x);
de[x]++,de[y]++;
}
queue q;
for(int i=1;i<=n;i++)
if(de[i]
1)q.push(i),v[i]=1;
while(q.size())
{
int x=q.front();
q.pop();
for(int y:adj[x])
if(--de[y]==1)q.push(y),v[y]=1;
}
LL res=1lln(n-1);
for(int i=1;i<=n;i++)
if(!v[i])
{
int sz=dfs(i,0);
res-=1llsz(sz-1)/2;
}
cout<<res<<"\n";
}
return 0;
}

  • 时间复杂度:\(O(n)\)

代码

// Problem: E. Number of Simple Paths
// Contest: Codeforces - Codeforces Round #686 (Div. 3)
// URL: https://codeforces.com/contest/1454/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=2e5+5;
int t,n,de[N],sz[N];
bool v[N];
vector<int> adj[N];
int dfs(int x,int fa)
{
	sz[x]=1;
	for(int y:adj[x])
	{
		if(!v[y]||y==fa)continue;
		dfs(y,x);
		sz[x]+=sz[y];
	}
	return sz[x];
}
int main()
{
    for(cin>>t;t;t--)
    {
    	cin>>n;
    	for(int i=1;i<=n;i++)adj[i].clear(),de[i]=v[i]=sz[i]=0;
    	for(int i=1;i<=n;i++)
    	{
    		int x,y;
    		cin>>x>>y;
    		adj[x].pb(y),adj[y].pb(x);
    		de[x]++,de[y]++;
    	}
    	queue<int> q;
    	for(int i=1;i<=n;i++)
    		if(de[i]==1)q.push(i),v[i]=1;
    	while(q.size())
    	{
    		int x=q.front();
    		q.pop();
    		for(int y:adj[x])
    			if(--de[y]==1)q.push(y),v[y]=1;
    	}
    	LL res=1ll*n*(n-1);
    	for(int i=1;i<=n;i++)
    		if(!v[i])
    		{
    			int sz=dfs(i,0);
    			res-=1ll*sz*(sz-1)/2;
    		}
    	cout<<res<<"\n";
    }
    return 0;
}
posted @ 2022-08-10 10:02  zyy2001  阅读(22)  评论(0编辑  收藏  举报