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
template
template
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 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
for(int i=1;i<=n;i++)
if(de[i]
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;
}