2018.08.20高二互测

2018.08.20 NOIp模拟赛

GKK大佬出的毒瘤题,烧脑。全是原题就不要密码保护了。

第一题

T1链接

​ 一张图,每条边有代价也有限制,遍历过的点可以解锁这些限制,求最短路。这是一道套路题,平时根本没见过,考场上因为一个状态或错了调了好久好久。对每个点状压记个状态判断能不能走这条边就行了。

code

#include<bits/stdc++.h>
#define Set(a, b) memset(a, b, sizeof (a))
#define fir first
#define sec second
#define mp make_pair
#define For(i, j, k) for(int i = j; i <= k; ++i)
#define Travel(i, u) for(int i = beg[u], v = to[i]; i; i = nex[i], v = to[i])
using namespace std;

inline int read() {
	int x = 0, p = 1; char c = getchar();
	for(; !isdigit(c); c = getchar()) if(c == '-') p = -1;
	for(; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
	return x *= p;
}

template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }

inline void File() {
	freopen("dalao.in", "r", stdin);
	freopen("dalao.out", "w", stdout);
}

typedef pair<int, int> PII;
const int N = 200 + 10, M = 6e3 + 10;
const int maxp = (1 << 13) + 10, inf = 0x7f7f7f7f;
int e = 1, beg[N], nex[M], to[M], w[M], stt[M];
int vis[N][maxp], dis[N][maxp], st[N];
int n, m, p, k;

inline void add(int x, int y, int z) {
	to[++ e] = y, nex[e] = beg[x], beg[x] = e, w[e] = z;
}

inline void spfa() {
	Set(vis, 0), Set(dis, 127);
	queue<PII> Q; Q.push(mp(st[1], 1)), vis[1][st[1]] = 1, dis[1][st[1]] = 0; 

	while (!Q.empty()) {
		PII u = Q.front(); Q.pop(), vis[u.sec][u.fir] = 0;
		Travel(i, u.sec) {
			int nst = u.fir | st[v];
			if (dis[v][nst] > dis[u.sec][u.fir] + w[i] && (stt[i] | u.fir) == u.fir) {
				dis[v][nst] = dis[u.sec][u.fir] + w[i];	
				if (!vis[v][nst]) vis[v][nst] = 1, Q.push(mp(nst, v));
			}
		} 
	}
}

int main() {
	File();
	cin >> n >> m >> p >> k;
	For(i, 1, k) {
		int pos = read(), num = read(), x;
		For(i, 1, num) x = read(), st[pos] |= (1 << (x - 1));
	}
	For(i, 1, m) {
		int x = read(), y = read(), z = read(), num = read(), a, s = 0;
		For(i, 1, num) a = read(), s |= (1 << (a - 1));
		add(x, y, z), stt[e] = s;
		add(y, x, z), stt[e] = s;
	}
	spfa();
	int ans = inf;
	For(i, 0, (1 << p) - 1) chkmin(ans, dis[n][i]);
	printf("%d\n", ans == inf ? -1 : ans);
	return 0;
}

第二题

T2链接

​ 用\(~n~\)个数去匹配\(~m~\)个数对,可以选择匹配与否,\(\sum ~[a_i > b_j] \times (a_i - b_j + c_j)~\)的最大值。我考场上想了一个贪心,把数对按\(~c_i - b_i~\)从大到小排序,每次二分一个满足条件的最小的\(~a~\)去匹配,当\(~(a_i - b_j + c_j) > 0~\)是计入答案,最后计算可以通过更换剩余的\(~a~\)而产生的更大的贡献。

其实这个离正解贪心差不多了,但我太菜了没想到一个细节:就算一个\(~(a_i - b_j + c_j)~\)的贡献是负的,之后也可以通过更换\(~a~\)来产生更大的贡献。我那样打就导致大样例答案总是小一点,于是就滚去打阶乘的\(~20pts~\)的暴力了。所以正解贪心就是:先把数对按\(~c_i - b_i~\)从大到小排序, 每次二分\(~a~\)看这个数对是否满足条件,满足就记下来,最后再一起算答案,每次用最大的\(~a~\)去匹配先前记下来的数对。我好菜啊。。。

code

#include<bits/stdc++.h>
#define For(i, j, k) for(int i = j; i <= k; ++i)
#define Forr(i, j, k) for(int i = j; i >= k; --i)
using namespace std;

inline int read() {
	int x = 0, p = 1; char c = getchar();
	for(; !isdigit(c); c = getchar()) if(c == '-') p = -1;
	for(; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
	return x *= p;
}

inline void File() {
	freopen("winner.in", "r", stdin);
	freopen("winner.out", "w", stdout);
}

typedef long long ll;
const int N = 1e5 + 10;
int a[N], n, m, b[N], c[N], val[N], cnt;
struct node { int b, c; } P[N];
multiset<ll> S;
inline bool cmp(const node &a, const node &b) { return a.c - a.b > b.c - b.b; }
inline bool cmpa(const int &a, const int &b) { return a > b; }


int main() {
	File();
	n = read(), m = read();
	For(i, 1, n) S.insert(a[i] = read());
	For(i, 1, m) b[i] = read(), c[i] = read(), P[i] = (node) {b[i], c[i]};

	sort(P + 1, P + 1 + m, cmp);
	
	For(i, 1, m) {
		auto it = S.upper_bound(P[i].b);
		if (it == S.end()) continue;
		else val[++ cnt] = P[i].c - P[i].b, S.erase(it);
	}

	sort(a + 1, a + 1 + n, cmpa);
	
	ll ans = 0;
	For(i, 1, cnt) if (val[i] + a[i] > 0) ans += val[i] + a[i];
	printf("%lld\n", ans);
	return 0;
}

第三题

T3链接

​ 先%%%HYJ大佬!给出\(~m, ~a, ~b, ~c~\)\(~a, ~b, ~c~\)两两互质,求解\(~x ^ a + y ^ b \equiv z^c ~(mod ~m)~\). 可以构造使\(~x = 2 ^ {kb}, ~ y = 2 ^ {ka}, z = 2 ^ p~\), 那么原式化为\(~2 ^ {kab + 1} \equiv 2 ^ {pc}~\), 则特判掉\(~m~\)\(~2 ^ k~\)次幂,\(~k \in N^{+}\)的情况。剩余则有\(~kab + 1 = pc~\), 转化一下就是扩欧了。膜烂hyj考场上火速ak并教会我!

code

#include<bits/stdc++.h>
#define For(i, j, k) for(int i = j; i <= k; ++i)
#define Forr(i, j, k) for(int i = j; i >= k; --i)
using namespace std;

inline int read() {
	int x = 0, p = 1; char c = getchar();
	for(; !isdigit(c); c = getchar()) if(c == '-') p = -1;
	for(; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
	return x *= p;
}

inline void File() {
	freopen("guess.in", "r", stdin);
	freopen("guess.out", "w", stdout);
}

typedef long long ll;
int mod, a, b, c;

inline ll qpow(ll a, ll b) {
	ll res = 1;
	if (b < 0) b = -b;
	for (res = 1; b; a = a * a % mod, b >>= 1) 
		if (b & 1) res = res * a % mod;
	return res;
}

inline void BF_Solve() {
	int flag = 0;
	For(x, 1, mod - 1) {
		For(y, 1, mod - 1) {
			For(z, 1, mod - 1) {
				if ((qpow(x, a) + qpow(y, b)) % mod == qpow(z, c) % mod) {
					printf("%d %d %d\n", x, y, z);
					flag = 1; break;
				}	
			}	
			if (flag) break;
		}
		if (flag) break;
	}
}

ll exgcd(ll a, ll b, ll &x, ll &y) {
	if (b == 0) return x = 1, y = 0, a;
	ll d = exgcd(b, a % b, x, y), tmp;
	tmp = x, x = y, y = tmp - a / b * y;
	return d;
}

int main() {
	File();

	for (int Case = read(); Case --; ) {
		mod = read(), a = read(), b = read(), c = read();
		int tt = mod, x, y, z;
		while (!(tt & 1)) tt /= 2;

		if (tt != 1) {
			ll A = 1ll * a * b, B = c, X, Y, d;
			d = exgcd(B, A, X, Y);
			while (X < 0 || Y > 0) X += A, Y -= B;
			x = qpow(2, 1ll * Y * b), y = qpow(2, 1ll * Y * a), z = qpow(2, X);					

		} else {
			int res = mod >> 1;
			if (a > 1) x = res, y = z = 1;
			if (a == 1 && b > 1) y = res, x = z = 1;
			if (a == 1 && b == 1 && c > 1) x = y = z = res;
			if (a == 1 && b == 1 && c == 1) x = 1, y = 2, z = 3;	
		}
		printf("%d %d %d\n", x, y, z);
	}

	return 0;
}

​ 今天整个神游,第一题十点才调出来,大概是昨天晚上改AGC005F到一点的还没调出来的后遗症,以后考试要保持好精力,不然得不偿失。GKK不愧是gay, 只是题面少了谁,美中不足。

posted @ 2018-08-20 21:55  LSTete  阅读(144)  评论(0编辑  收藏  举报