Gym100851G Generators 思维 (鸽笼原理)
Posted aya-uchida
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym100851G Generators 思维 (鸽笼原理)相关的知识,希望对你有一定的参考价值。
网址:https://codeforces.com/gym/100851
题意:
考虑如下线性同余发生器:$x=(a*x+b)mod$ $c$,给出$1e4$个线性同余发生器,在这些线性同余发生器生成的数的序列中每一个序列都任意挑一个数,使得它们的和最大并且不被$k$整除,输出和的值和各个位置,如果不存在输出$-1$。$cleq1e3$。
题解:
线性同余发生器的值一定在不超过$c$个数就重复循环。所以只需要取其生成的前$c$个数的第k大。如果它们的和不被$k$整除,直接输出即可,如果被$k$整除,找到某个序列的第二大,使其和第一大的差值最小,且差值不被$k$整除,换上这个第二大即可。
(很奇怪,我不知道为什么我排序了还不能直接按顺序取第二大而是需要更新,不然会$WA$)。
AC代码:
#include <bits/stdc++.h> using namespace std; const int N = 1e4 + 5; typedef long long ll; vector<pair<int, int> >v; pair<int, int>p[N], dif[N]; bool vis[1005]; int main() { #ifndef _Aya //freopen("generators.in", "r", stdin); //freopen("generators.out", "w", stdout); #endif int n, k, a, b, c, x; scanf("%d%d", &n, &k); for (int i = 1; i <= n; ++i) { memset(vis, 0, sizeof(vis)); v.clear(); scanf("%d%d%d%d", &x, &a, &b, &c); v.push_back(make_pair(x, 0)); vis[x] = 1; for (int j = 1; j < c; ++j) { x = (a * x + b) % c; if (!vis[x]) v.push_back(make_pair(x, j)), vis[x] = 1; else break; } dif[i] = make_pair(-1, -1); sort(v.begin(), v.end(), greater<pair<int, int> >()); p[i] = v[0]; for (int j = 1; j < v.size(); ++j) if ((v[0].first - v[j].first) % k != 0 && v[j].first > dif[i].first) dif[i] = v[j]; assert(p[i].first > dif[i].first); } ll sum = 0; for (int i = 1; i <= n; ++i) sum += p[i].first; if (sum % k) { printf("%lld ", sum); for (int i = 1; i <= n; ++i) printf("%d%c", p[i].second, " "[i == n]); } else { int minn = 1e4, minpos = 0; for (int i = 1; i <= n; ++i) if (dif[i].second != -1 && p[i].first - dif[i].first < minn) minn = p[i].first - dif[i].first, minpos = i; if (!minpos) printf("-1 "); else { p[minpos] = dif[minpos]; sum -= minn; printf("%lld ", sum); for (int i = 1; i <= n; ++i) printf("%d%c", p[i].second, " "[i == n]); } } return 0; }
以上是关于Gym100851G Generators 思维 (鸽笼原理)的主要内容,如果未能解决你的问题,请参考以下文章
Gym 101503C Twisting the Number(思维+枚举)
Gym 100247BSimilar Strings(哈希+思维)
GYM 101350 F. Monkeying Around(线段树 or 思维)