• 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, 只是题面少了谁,美中不足。

  • 相关阅读:
    面向对象设计与实用的思考(主动对象与被动对象)
    改进弧长法 判断点是否在多边形内 c#代码
    PaintCode begin
    kiwivm putty lnmp
    初心已变,我也不是当时的我
    spfa
    tree dp
    开心就好之修行ing
    MIME 参考手册
    TypeScript学习和参考手册
  • 原文地址:https://www.cnblogs.com/LSTete/p/9508375.html
Copyright © 2020-2023  润新知