当前位置: 代码迷 >> 综合 >> 2019ccpc哈尔滨 E - Exchanging Gifts Gym 线性求解+unorderdmap
  详细解决方案

2019ccpc哈尔滨 E - Exchanging Gifts Gym 线性求解+unorderdmap

热度:91   发布时间:2023-11-28 03:03:42.0

题目链接

Problem - E - Codeforces

题目大意

有两种操作 第一种是列出一个序列 第二种是合并之前出现的序列生成一个新的序列

问你最后序列的快乐值是多少

快乐值定义是 将序列随意排序后最大的与之前位置不同的元素个数

题目思路

经过观察发现

最大快乐值

数量最多的元素数量=maxv

总元素数量=tot

当maxv<tot/2时 快乐值=tot

否则快乐值 =tot-(maxv-(tot-maxv))

列出如下之图可看得更明白

有上图到下图 明显不快乐值为 最大的数量5 -剩余数量4=1

快乐值=9-1=8

问题是如何找到各个元素数量

由于每个操作2可以吸收两个序列

可以很容易想到拓补

但是该题有一个条件就是2操作的对象序号小于 i

那么该题就不需要拓扑了 直接从n到1线性求解

设置num【n】=1

若该点是操作2则将操作对象的num+=num【i】

若该点是操作1则该点包含所有的点的数量+=num【i】

若某一个点num【i】==0 就跳过

这样的时间复杂度是O(N+K)

但由于读入数量级的问题 很容易T

因此我用了一个超级快读(注意该快读无法读入其他类型)

static char buf[100000],*pa=buf,*pd=buf;
#define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{register int x(0);register char c(gc);while(c<'0'||c>'9')c=gc;while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc;return x;
}

题目代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int t,n,m,T,q,x,y;int lef[maxn],inlj[maxn];
ll num[maxn];
ll tot,maxv;
unordered_map<int ,ll >mp;
static char buf[100000],*pa=buf,*pd=buf;
#define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{register int x(0);register char c(gc);while(c<'0'||c>'9')c=gc;while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc;return x;
}
//void dfs(int floor)
//{
//	if(lef[floor])
//	for(int i=0;i<e[floor];i++)
//	{
//		
//	}
//}
vector<int >v[maxn];
int main()
{T=read();while(T--){n=read();mp.clear();tot=maxv=0;for(int i=1;i<=n;i++){t=read();v[i].clear();lef[i]=num[i]=0;if(t==1){q=read();for(int j=0;j<q;j++){x=read();v[i].push_back(x);} }else if(t==2){x=read();y=read();v[i].push_back(x);v[i].push_back(y);lef[i]=1;}} num[n]=1;if(lef[n]){//dfs(n);for(int i=n;i>=1;i--){if(num[i]==0)continue;int floor=i;if(lef[floor]==1){num[v[floor][0]]+=num[i];num[v[floor][1]]+=num[i];}else {for(int j=0;j<v[floor].size();j++){int y=v[floor][j];mp[y]+=num[i];maxv=max(maxv,mp[y]);tot+=num[i];}}} }else {int floor=1;for(int j=0;j<v[floor].size();j++){int y=v[floor][j];mp[y]+=num[floor];maxv=max(maxv,mp[y]);tot+=num[floor];}}if(maxv<=(tot)/2){printf("%lld\n",tot);}else {ll tmp=maxv-(tot-maxv);printf("%lld\n",tot-tmp);}}return 0;
}