• 2018冬令营模拟测试赛(十四)


    2018冬令营模拟测试赛(十四)

    [Problem A]prime

    试题描述

    T_T

    Q_Q

    输入

    见“试题描述

    输出

    见“试题描述

    输入示例

    见“试题描述

    输出示例

    见“试题描述

    数据规模及约定

    见“试题描述

    题解

    考虑 (sum_{i=1}^n { 2^{f(i)} }) 这个式子的组合意义,我们发现 (2^{f(i)}) 的意义就是 (i) 这个数的每个不同质因子都有选和不选两种方案,(2^{f(i)}) 即方案数,也就是说 (i) 的无平方因子的约数个数。形式化地,即

    [2^{f(i)} = sum_{d|i} { mu^2(d) } ]

    我们代入到原式当中,得到

    [sum_{i=1}^n { 2^{f(i)} } \\ = sum_{i=1}^n { sum_{d|i} { mu^2(d) } } \\ = sum_{d=1}^n { mu^2(d) sum_{d|i, i le n} { 1 } } \\ = sum_{d=1}^n { mu^2(d) lfloor frac{n}{d} floor } ]

    然而这时 (mu^2(d)) 的前缀和并不好处理,我们考虑给它变个形。先理解一下 (mu^2(d)) 的意义,(mu^2(d) = 1 Leftrightarrow d 没有平方因子 Leftrightarrow d 的最大完全平方约数 = 1),假设 (g(d)) 就是 (d) 的最大完全平方约数,于是上面的条件又等价于 (sqrt{g(d)} = 1),于是可以把式子变成如下形态

    [mu^2(d) \\ = [sqrt{g(d)} = 1] \\ = sum_{i|sqrt{g(d)}} { mu(i) } \\ = sum_{i^2|g(d)} { mu(i) } \\ = sum_{i^2|d} { mu(i) } ]

    然后代入到上式中,得到

    [sum_{d=1}^n { mu^2(d) lfloor frac{n}{d} floor } \\ = sum_{d=1}^n { lfloor frac{n}{d} floor sum_{i^2|d} { mu(i) } } \\ = sum_{i=1}^{lfloor sqrt{n} floor} { mu(i) sum_{i^2|d, d le n} { lfloor frac{n}{d} floor } } \\ = sum_{i=1}^{lfloor sqrt{n} floor} { mu(i) sum_{d=1}^{lfloor frac{n}{i^2} floor} { lfloor frac{lfloor frac{n}{i^2} floor}{d} floor } } ]

    于是可以预处理 (mu(i)) 的前缀和,然后分段算后面那坨 sigma,sigma 里面的也暴力分段算,最后时间复杂度是 (O(sqrt{n}log n)) 的(这个可以积分一下算出来)。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    #define LL long long
    
    LL read() {
    	LL x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 1000010
    #define MOD 998244353
    #define LL long long
    
    bool vis[maxn];
    int prime[maxn], cp, mu[maxn], su[maxn];
    
    void init(int n) {
    	mu[1] = su[1] = 1;
    	rep(i, 2, n) {
    		if(!vis[i]) prime[++cp] = i, mu[i] = -1;
    		for(int j = 1; j <= cp && i * prime[j] <= n; j++) {
    			vis[i*prime[j]] = 1;
    			if(i % prime[j] == 0) {
    				mu[i*prime[j]] = 0;
    				break;
    			}
    			mu[i*prime[j]] = -mu[i];
    		}
    		su[i] = su[i-1] + mu[i];
    	}
    	return ;
    }
    
    int calc(LL n) {
    	int ans = 0;
    	for(LL i = 1; i <= n; ) {
    		LL r = min(n / (n / i), n);
    		ans += (LL)(r - i + 1) * (n / i) % MOD;
    		if(ans >= MOD) ans -= MOD;
    		i = r + 1;
    	}
    	return ans;
    }
    
    int main() {
    	LL n = read();
    	int m = sqrt(n + .5);
    	
    	init(m);
    	int ans = 0;
    	for(int i = 1; i <= m; ) {
    		int r = min((int)sqrt(n / (n / ((LL)i * i)) + .5), m);
    		ans += ((LL)(su[r] - su[i-1]) * calc(n / ((LL)i * i)) % MOD + MOD) % MOD;
    		if(ans >= MOD) ans -= MOD;
    		i = r + 1;
    	}
    	
    	printf("%d
    ", ans);
    	
    	return 0;
    }
    

    [Problem B]final

    试题描述

    TwT

    QwQ

    输入

    见“试题描述

    输出

    见“试题描述

    输入示例

    见“试题描述

    输出示例

    见“试题描述

    数据规模及约定

    见“试题描述

    补充:(1 le m le 3n)

    题解

    这题和某道我之前做过的题(那场比赛的 C 题)做法一样,我们发现每个转移都是平移然后叠加上去,所以可以看成多项式乘上 (x^t),然后将所有状态、转移都转化成点值就可以直接做矩阵快速幂了。注意这题不需要循环卷积,直接开成 (3n) 大小 FFT 就好了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 2510
    #define maxm 8200
    #define MOD 998244353
    #define Groot 3
    #define LL long long
    
    int A[3], all, cbit[8], trans[8][8];
    
    bool Can(int s) {
    	rep(i, 0, 1) if((s >> i & 1) && (s >> i + 1 & 1) && ((A[1] & 1) || (A[1] >> 2 & 1))) return 0;
    	return 1;
    }
    
    int Pow(int a, int b) {
    	int ans = 1, t = a;
    	while(b) {
    		if(b & 1) ans = (LL)ans * t % MOD;
    		t = (LL)t * t % MOD; b >>= 1;
    	}
    	return ans;
    }
    int N, brev[maxm];
    void FFT(int *a, int len, int tp) {
    	int n = 1 << len;
    	rep(i, 0, n - 1) if(i < brev[i]) swap(a[i], a[brev[i]]);
    	rep(i, 1, len) {
    		int wn = Pow(Groot, MOD - 1 >> i);
    		if(tp < 0) wn = Pow(wn, MOD - 2);
    		for(int j = 0; j < n; j += 1 << i) {
    			int w = 1;
    			rep(k, 0, (1 << i >> 1) - 1) {
    				int la = a[j+k], ra = (LL)w * a[j+k+(1<<i>>1)] % MOD;
    				a[j+k] = (la + ra) % MOD;
    				a[j+k+(1<<i>>1)] = (la - ra + MOD) % MOD;
    				w = (LL)w * wn % MOD;
    			}
    		}
    	}
    	if(tp < 0) rep(i, 0, n - 1) a[i] = (LL)a[i] * Pow(n, MOD - 2) % MOD;
    	return ;
    }
    
    void prod(int *a, const int *b, const int *c) {
    	rep(i, 0, N - 1) {
    		a[i] += (LL)b[i] * c[i] % MOD;
    		if(a[i] >= MOD) a[i] -= MOD;
    	}
    	return ;
    }
    struct Matrix {
    	int A[8][8][maxm], n, m;
    	Matrix() {}
    	Matrix(int _, int __): n(_), m(__) {}
    	Matrix operator = (const Matrix& t) {
    		n = t.n; m = t.m;
    		rep(i, 0, n) rep(j, 0, m) rep(k, 0, N - 1) A[i][j][k] = t.A[i][j][k];
    		return *this;
    	}
    	Matrix operator * (const Matrix& t) const {
    		Matrix ans(n, t.m);
    		rep(i, 0, ans.n) rep(j, 0, ans.m) {
    			int *a = ans.A[i][j];
    			rep(k, 0, N - 1) a[k] = 0;
    			rep(k, 0, m) prod(a, A[i][k], t.A[k][j]);
    		}
    		return ans;
    	}
    	Matrix operator *= (const Matrix& t) {
    		*this = *this * t;
    		return *this;
    	}
    } base(7, 0), tr(7, 7);
    Matrix PowM(Matrix& a, int b) {
    	Matrix ans = a, t = a; b--;
    	while(b) {
    		if(b & 1) ans *= t;
    		t *= t; b >>= 1;
    	}
    	return ans;
    }
    
    int main() {
    	int n = read(), m = read();
    	rep(i, 0, 2) rep(j, 0, 2) A[i] |= (read() << j);
    	
    	all = 7;
    	memset(trans, -1, sizeof(trans));
    	rep(i, 1, all) cbit[i] = cbit[i-(i&-i)] + 1;
    	rep(s, 0, all) if(Can(s)) {
    		int ban = 0;
    		rep(i, 0, 2) if(s >> i & 1) ban |= i < 2 ? (A[2] >> 1 - i) : (A[2] << 1);
    		rep(ts, 0, all) if(Can(ts) && !(ban & ts)) {
    			int tb = 0;
    			rep(i, 0, 2) if(ts >> i & 1) tb |= i < 2 ? (A[0] >> 1 - i) : (A[0] << 1);
    			if(tb & s) continue;
    			trans[ts][s] = cbit[ts];
    			// printf("%d -> %d  %d
    ", s, ts, trans[ts][s]);
    		}
    	}
    	
    	N = 1; int len = 0;
    	while(N <= 3 * n) N <<= 1, len++;
    	rep(i, 0, N - 1) brev[i] = (brev[i>>1] >> 1) | ((i & 1) << len >> 1);
    	
    	memset(base.A, 0, sizeof(base.A));
    	base.A[0][0][0] = 1;
    	FFT(base.A[0][0], len, 1);
    	
    	memset(tr.A, 0, sizeof(tr.A));
    	rep(ts, 0, all) rep(s, 0, all) {
    		if(trans[ts][s] >= 0) tr.A[ts][s][trans[ts][s]] = 1;
    		FFT(tr.A[ts][s], len, 1);
    		// printf("tr[%d][%d]: ", ts, s); rep(i, 0, N - 1) printf("%d%c", tr.A[ts][s][i], i < N - 1 ? ' ' : '
    ');
    	}
    	
    	base = PowM(tr, n) * base;
    	int ans = 0;
    	rep(s, 0, all) {
    		FFT(base.A[s][0], len, -1);
    		// printf("%d: ", s); rep(i, 0, N - 1) printf("%d%c", base.A[s][0][i], i < N - 1 ? ' ' : '
    ');
    		ans += base.A[s][0][m];
    		if(ans >= MOD) ans -= MOD;
    	}
    	printf("%d
    ", ans);
    	
    	return 0;
    }
    

    [Problem C]gift

    试题描述

    TAT

    QAQ

    输入

    见“试题描述

    输出

    见“试题描述

    输入示例

    见“试题描述

    输出示例

    见“试题描述

    数据规模及约定

    见“试题描述

    这题出锅啦,答案下取整改成上取整减 (1)

    题解

    看到分数就分数规划(二分),现在就是判断是否存在方案使得 (frac{B}{A} > x),移项得到 (B - Ax > 0),于是最大化 (B - Ax),我们先将所有的好感度都选上,然后就有两种代价,一个是牺牲某个好感度,一个是买某个物品,于是这就是经典的最小割模型了。

    用最大权闭合子图的模型会有 (n + m + 2) 个点,就 T 飞了,要优化。每条边可以用方程算一下定多少流量,这样就只有 (n + 2) 个点了,然后把重边缩掉卡卡常数就 A 了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <map>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
        if(Head == Tail) {
            int l = fread(buffer, 1, BufferSize, stdin);
            Tail = (Head = buffer) + l;
        }
        return *Head++;
    }
    int read() {
        int x = 0, f = 1; char c = Getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
        return x * f;
    }
    
    #define maxn 204010
    #define maxm 416010
    #define oo 2147483647
    
    struct Edge {
    	int from, to, flow;
    	Edge() {}
    	Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
    };
    struct Dinic {
    	int s, t, n, m, head[maxn], nxt[maxm];
    	Edge es[maxm];
    	int vis[maxn], Q[maxn], hd, tl;
    	int cur[maxn];
    	
    	void init() {
    		m = 0; memset(head, -1, sizeof(head));
    		return ;
    	}
    	void setn(int _) {
    		n = _;
    		return ;
    	}
    	
    	void AddEdge(int a, int b, int c, int revc = 0) {
    		es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
    		es[m] = Edge(b, a, revc); nxt[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	
    	bool BFS() {
    		memset(vis, 0, sizeof(vis));
    		vis[t] = 1;
    		hd = tl = 0; Q[++tl] = t;
    		while(hd < tl) {
    			int u = Q[++hd];
    			for(int i = head[u]; i != -1; i = nxt[i]) {
    				Edge& e = es[i^1];
    				if(!vis[e.from] && e.flow) vis[e.from] = vis[u] + 1, Q[++tl] = e.from;
    			}
    		}
    		return vis[s] > 1;
    	}
    	
    	int DFS(int u, int a) {
    		if(u == t || !a) return a;
    		int flow = 0, f;
    		for(int& i = cur[u]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(vis[e.to] == vis[u] - 1 && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	
    	int MaxFlow(int _s, int _t) {
    		s = _s; t = _t;
    		int flow = 0;
    		while(BFS()) {
    			rep(i, 1, n) cur[i] = head[i];
    			flow += DFS(s, oo);
    		}
    		return flow;
    	}
    } sol;
    
    #define maxgift 4010
    #define maxcond 200010
    #define pii pair <int, int>
    #define x first
    #define y second
    #define mp(x, y) make_pair(x, y)
    
    int CntP;
    struct Point {
    	int id;
    	Point(): id(0) {}
    	int p() { return id ? id : id = ++ CntP; }
    } gift[maxgift], S, T;
    int n, m, sum, mn, price[maxgift], gid[maxgift], half[maxcond], val[maxcond], deg[maxgift];
    map <pii, int> cond;
    
    bool check(int x) {
    	for(int i = 0; i < sol.m; i += 2) sol.es[i].flow += sol.es[i^1].flow, sol.es[i^1].flow = 0;
    	rep(i, 1, n) sol.es[gid[i]].flow = price[i] * x;
    	rep(i, 1, m) if(half[i] >= 0) sol.es[half[i]].flow = sol.es[half[i]^1].flow = val[i];
    	int flow = sol.MaxFlow(S.p(), T.p());
    	return sum - flow > 0;
    }
    
    int main() {
    	n = read(); m = read(); sum = 0; mn = oo;
    	sol.init();
    	rep(i, 1, n) gid[i] = sol.m, sol.AddEdge(S.p(), gift[i].p(), price[i] = read() << 1), mn = min(mn, price[i]);
    	memset(half, -1, sizeof(half));
    	rep(i, 1, m) {
    		int a = read(), b = read(); int now = read();
    		if(a > b) swap(a, b);
    		if(!cond.count(mp(a, b))) cond[mp(a,b)] = i;
    		val[cond[mp(a,b)]] += now;
    		deg[a] += now; deg[b] += now;
    		sum += now << 1;
    	}
    	for(map <pii, int> :: iterator i = cond.begin(); i != cond.end(); i++)
    		half[i->y] = sol.m, sol.AddEdge(gift[i->x.x].p(), gift[i->x.y].p(), val[i->y], val[i->y]);
    	rep(i, 1, n) sol.AddEdge(gift[i].p(), T.p(), deg[i]);
    	sol.setn(CntP);
    	
    	int l = 0, r = sum / mn + 1;
    	while(r - l > 1) {
    		int mid = l + r >> 1;
    		if(check(mid)) l = mid; else r = mid;
    	}
    	printf("%d
    ", l);
    	
    	return 0;
    }
    
  • 相关阅读:
    129 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 02 懒汉式的代码实现
    128 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 01 饿汉式的代码实现
    127 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 02 单例模式概述 01 单例模式的定义和作用
    126 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 01 设计模式概述 01 设计模式简介
    125 01 Android 零基础入门 02 Java面向对象 05 Java继承(下)05 Java继承(下)总结 01 Java继承(下)知识点总结
    leetcode-----121. 买卖股票的最佳时机
    leetcode-----104. 二叉树的最大深度
    Json串的字段如果和类中字段不一致,如何映射、转换?
    Mybatis-Plus的Service方法使用 之 泛型方法default <V> List<V> listObjs(Function<? super Object, V> mapper)
    模糊查询
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8278549.html
Copyright © 2020-2023  润新知