题目链接
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);
}
}
}