2019CCPC哈尔滨 Exchanging Gifts 递推,map

题目链接

https://vjudge.net/problem/Gym-102394E

题意

给定n个序列,给出方式有两种:直接给定m个数字作为序列si,或者给定j,k,使si=sj+sk。

对sn任意排序,最多能使多少个位置上的数字与之前不同?

思路

先记录输入,vector数组存储第一种方式给定的序列。

从后往前递推出每一个序列的使用次数并记录。

使用unordered_map统计出现次数最多的数字,并记录序列总长度

答案为min(len,2len-2cnt)

教训/收获

  • map除了建立映射以外还保证了内部元素的有序,所以查询插入复杂度为logn,c++11支持hash原理的unordered_map查询插入复杂度为O(1)
  • 善用vector可以节省很大的空间开销,1e8 int 数组约400M
  • 有思路就写,做错好过什么都不做

代码

#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<unordered_map>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=1005000;
	const int inf=0x3f3f3f3f;
	int n,m;
	ll cmd[maxn][3];
	vector<ll>v[maxn];
	ll need[maxn];
	queue<ll>q;
	unordered_map<ll,ll>mp;
	template <typename T>
	void read(T &x){
    
    
    	x=0;
    	char ch=getchar();
    	ll f=1;
	    while(!isdigit(ch)){
    
    
	        if(ch=='-')
	            f*=-1;
	        ch=getchar();
	    }
	    while(isdigit(ch)){
    
    
	        x=x*10+ch-48;
	        ch=getchar();
	    }
	    x*=f;
	}
	signed main(){
    
    
		int tn;
		read(tn);
		while(tn--){
    
    
			read(n);
			for(int i=1;i<=n;i++){
    
    
				read(cmd[i][0]);
				if(cmd[i][0]==1){
    
    
					read(m);
					for(int j=0;j<m;j++){
    
    
						ll tmp;
						read(tmp);
						v[i].push_back(tmp);
					}
				}
				else{
    
    
					scanf("%lld%lld",&cmd[i][1],&cmd[i][2]);
				}
			}
			for(int i=0;i<=n;i++)
				need[i]=0;
			need[n]=1;
			
			for(int i=n;i>=1;i--){
    
    
				if(cmd[i][0]==1)
					continue;
				need[cmd[i][1]]+=need[i];
				need[cmd[i][2]]+=need[i];
			}
		
			ll cnt=0,ma=-inf;
			for(int i=1;i<=n;i++){
    
    
				if(need[i]){
    
    
					for(auto j:v[i])
						mp[j]+=need[i];
					cnt+=need[i]*v[i].size();
				}
			}
			cout<<cnt<<endl;
			for(int i=1;i<=n;i++)
				v[i].clear();
			for(auto i:mp){
    
    
				ma=max(i.second,ma);	
			}
			mp.clear();
			if(2*ma<cnt){
    
    
				printf("%lld\n",cnt);
			}
			else{
    
    
				printf("%lld\n",2*cnt-2*ma);
			}
		} 
	}


猜你喜欢

转载自blog.csdn.net/TheSunspot/article/details/109037048