P8269题解

题面描述

对于第 \(i\) 数,如果 \(p_i\) 在他之前,那就产生 \(v_i\) 的贡献。求这个贡献值最大。

Solution

我们可以将此问题转化为用所有的贡献值-所有排列中最小的贡献值。

那么一个显然的思路,考虑在 \(v\)\(u\) 前会产生贡献时连一条 \(u \to v\) 的有向边。

  • 当且仅当形成环时,一定会产生贡献,题上说取最小,故我们在这个环上找到最小的不满值,累加入答案。

  • 当未形成环时,总有一种方式不会产生贡献。

因为每一个数出度入度只有 \(1\) ,所以一个数只可能在一个环上。所以我们在深搜时,每个点只需要搜一次,所以时间复杂度为 \(O(n)\)

在2022-06-19 21:36:16时到达最优解

Code

//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("inline")
#include<bits/stdc++.h>
#define re register
//#define int long long
#define fep(i,l,r) for(re int i=l;i<=r;++i)
#define For(i,u) for(re int i=head[u];i;i=e[i].nxt)
#define feb(i,r,l) for(re int i=r;i>=l;--i)
#define LL long long
using namespace std;
 
const int N = 1e5+5,mod = 1e9+7;
int n,to[N],c[N],s[N],top,pos[N]; bool vis[N],belong[N]; LL ans;
 
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e5+5; 

namespace quick {
#define tp template<typename Type>
	namespace in {
		inline char getc() {
			static char buf[1<<21],*p1=buf,*p2=buf;
			return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
		}
		inline int read(char *s) {
			*s=getc();
			while(isspace(*s)) {*s=getc();if(*s==EOF) return 0;}
			while(!isspace(*s)&&*s!=EOF) {s++;*s=getc();}
			*s='\0'; return 1;
		}
		tp inline int read(Type &x) {
			x=0;bool k=false;char c=getc();
			while(!isdigit(c)) {k|=(c=='-');c=getc();if(c==EOF) return 0;}
			while(isdigit(c)) {x=(x<<1)+(x<<3)+(c^48);c=getc();}
			x*=(k?-1:1); return 1;
		}
		template <typename Type,typename... Args>
		inline int read(Type &&t,Args &&...args) {
			return read(t)+read(args...);
		}
	}
	using in::read;
	namespace out {
		char buf[1<<21];int p1=-1;const int p2=(1<<21)-1;
		inline void flush() {
			fwrite(buf,1,p1+1,stdout);
			p1=-1;
		}
		inline void putc(const char &c) {
			if(p1==p2) flush();
			buf[++p1]=c;
		}
		inline void write(char *s) {
			while(*s!='\0') putc(*s),s++;
		}
		inline void write(const char *s) {
			while(*s!='\0') putc(*s),s++;
		}
		tp inline void write(Type x) {
			static char buf[30];int p=-1;
			if(x<0) {putc('-');x=-x;}
			if(x==0) putc('0');
			else for(;x;x/=10) buf[++p]=x%10+48;
			for(;p!=-1;p--) putc(buf[p]);
		}
		inline void write(const char &c) {putc(c);}
		template <typename Type,typename... Args>
		inline void write(const Type &t,const Args &...args) {
			write(t);write(args...);
		}
	}
	using out::write;
	using out::flush;
#undef tp
}
using namespace quick;

inline void dfs(int u)
{
	if(vis[u])
	{
		int minn=1e9;
		fep(i,pos[u],top) minn=min(minn,c[s[i]]),belong[s[i]]=true;;
		ans+=minn; return ;
	}
	if(belong[u])
	{
		fep(i,1,top) belong[s[i]]=true; return ;//一定要有这句,否则保证不了时间复杂度的线性
	}
	vis[u]=true; s[++top]=u; pos[u]=top;
	dfs(to[u]);
	vis[u]=false; --top;
}
 
signed main()
{
	read(n); LL sum=0;
	fep(i,1,n) read(to[i],c[i]),sum+=c[i];
	fep(i,1,n) if(!belong[i]) dfs(i);
	write(sum-ans);
	return flush(),0;
}
posted @ 2022-06-19 21:48  starrylasky  阅读(44)  评论(0)    收藏  举报