Exchanging Gifts(思维 + 拓扑排序)

Exchanging Gifts

[Link](Problem - E - Codeforces)

题意

给你n个操作,每个操作有两种类型,1. 1 m 接下来输入m个数表示这第i个序列是什么, 2. 2 a b 表示 第i个数列有第a个和第b个数列拼接而成。然后你可以对第n个序列进行操作,任意改变他的顺序,问操作后的数组最多有多少个位置的数与原数组相同位置的数不一样。

题解

因为可以随意改变顺序,所以发现当出现最多的数 m x mx mx的数量小于等于总数量 s u m / 2 sum/2 sum/2的时候,我们总可以使得所有的位置都和以前不一样,因此答案是 s u m sum sum,当 m x > s u m / 2 mx>sum/2 mx>sum/2的时候发现无论怎么换总有 m x ∗ 2 − s u m mx*2-sum mx2sum的数还会在原来的位置,因此答案是 ( s u m − m x ) ∗ 2 (sum-mx)*2 (summx)2

但是发现这个序列最长可达 1 e 18 1e18 1e18,我们肯定没法把这个序列直接搞出来。因为每一个合成的序列都是由两个子序列构成的,所以我们可以想办法搞出来对第n个序列有贡献的不由其他序列构成的序列被用了多少次,这样再去统计这些序列里数出现的次数即可。假设第 i i i序列被用了 k k k次那么构成第 i i i个序列的子序列被用的次数也要加上 k k k,怎么去统计这个次数呢,对于构成第i个序列的子序列 u , v u,v u,v可以从 i 向 u , v i向u,v iuv各连一条边,我们可以先以n为根把和第n个序列有关的序列都搜出来并统计每个序列的入度,然后做一次拓扑排序,可以保证当前这个点入队的时候一定没有其他的点再去更新他了,所以可以统计出每个序列被用的次数。然后用有用的基序列的次数去推每个数出现的次数,统计一下sum和mx就可以啦。

因为这道题的读入太多了,所以不用快读的话会T。

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath> 
#include <stack>
#include <iomanip>
#include <deque> 
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e6 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
LL cnt[N];
int d[N], op[N];
vector<int> col[N];
unordered_map<int, LL> res;
queue<int> q;
bool st[N];
void init() {
    while (q.size()) q.pop();
    for (int i = 1; i <= n; i ++ ) {
        h[i] = -1, d[i] = cnt[i] = op[i] = st[i] = 0;
        col[i].clear();
    }
    res.clear(), idx = 0;
}
void bfs() {
    q.push(n);
    st[n] = true;
    while (q.size()) {
        LL t = q.front(); q.pop();
        for (int i = h[t]; ~i; i = ne[i] ) {
            int j = e[i];
            d[j] ++;
            if (!st[j]) q.push(j), st[j] = true;
        }
    }
}
void topsort() {
    q.push(n);
    while (q.size()) {
        LL t = q.front(); q.pop();
        for (int i = h[t]; ~i; i = ne[i] ) {
            int j = e[i];
            cnt[j] += cnt[t];
            if (-- d[j] == 0) q.push(j);
        }
    }
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    int T;
    read(T);
    while (T -- ) {
        read(n);
        init();
        for (int i = 1; i <= n; i ++ ) {
            int a, b;
            read(op[i]);
            if (op[i] == 1) {
                read(b);
                for (int j = 0; j < b; j ++ ) read(a), col[i].push_back(a);
            }
            else {
                read(a), read(b);
                add(i, a), add(i, b);
            }
        }
        cnt[n] = 1;
        bfs(), topsort();
        for (int i = 1; i <= n; i ++ ) 
            if (cnt[i] && op[i] == 1) 
                for (auto x : col[i]) res[x] += cnt[i];
        LL sum = 0, mx = 0;
        for (auto x : res) {
            sum += x.y;
            if (x.y > mx) mx = x.y;
        }
        if (mx * 2 >= sum) cout << (sum - mx) * 2 << endl;
        else cout << sum << endl;
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用c++解决You surely know that there are N different currencies you can deal with in our city. Let us assign unique integer number from 1 to N to each currency. Then each exchange point can be described with 6 numbers: integer A and B - numbers of currencies it exchanges, and real RAB, CAB, RBA and CBA - exchange rates and commissions when exchanging A to B and B to A respectively. Nick has some money in currency S and wonders if he can somehow, after some exchange operations, increase his capital. Of course, he wants to have his money in currency S in the end. Help him to answer this difficult question. Nick must always have non-negative sum of money while making his operations. Input The first line contains four numbers: N - the number of currencies, M - the number of exchange points, S - the number of currency Nick has and V - the quantity of currency units he has. The following M lines contain 6 numbers each - the description of the corresponding exchange point - in specified above order. Numbers are separated by one or more spaces. 1 ≤ S ≤ N ≤ 100, 1 ≤ M ≤ 100, V is real number, 0 ≤ V ≤ 103. For each point exchange rates and commissions are real, given with at most two digits after the decimal point, 10-2 ≤ rate ≤ 102, 0 ≤ commission ≤ 102. Let us call some sequence of the exchange operations simple if no exchange point is used more than once in this sequence. You may assume that ratio of the numeric values of the sums at the end and at the beginning of any simple sequence of the exchange operations will be less than 104. Output If Nick can increase his wealth, output YES, in other case output NO.
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值