省选模拟 19/08/11

T1 

解:考场上想了一个 (因数个数)^ 3 的 DP,大概就是定义 f[gcd][lcm], 然后枚举当前因数选不选转移

考虑 gcd,lcm 的另一种形式,不妨设 m=\prod_i p_i ^ {a_i}

就是 对于每一个质因子,选出来的次数 max(c1, c2, c3 ... cn) = ai, min(c1, c2, ... cn) = 0

我们发现,n 的个数最多 15 个,意味着我们可以乱搞一波容斥

考虑全部的个数 - 不合法的个数

对于当前质因子 pi,钦定它只能选到 [0 -- ai] [1 -- ai ], [0 -- ai-1], 或者 [1 -- ai-1]

发现二三个限制对答案贡献是一样的,然后每个数是哪个限制,最后容斥一下就可以了

复杂度 O(3 ^ 15)

m = 1e18 需要用 pollard-rho 分解,但是我太菜+太懒暴力分解水过了,等复习一下pollard-Rho 再来补档

#include<bits/stdc++.h>
#define N 100050
#define M 20
using namespace std;
typedef long long ll;
const int Mod = 998244353;
int prim[N], isp[N], tot;
ll m; int a[M], cnt[M], k, s[M];
ll add(ll a, ll b){ return (a + b) % Mod;}
ll mul(ll a, ll b){ return a * b % Mod;}
void prework(){
	for(int i = 2; i <= N-50; i++){
		if(!isp[i]) prim[++tot] = i;
		for(int j = 1; j <= tot; j++){
			if(i * prim[j] > N-50) break;
			isp[i * prim[j]] = 1; if(i % prim[j] == 0) break;
		}
	} 
}
ll power(ll a, ll b){ ll ans = 1;
	for(;b;b>>=1){ if(b&1) ans = (ans*a) % Mod; a = (a*a) % Mod;}
	return ans;
}
ll ans = 0;
void dfs(int u, int tot, int op){
	if(u == k + 1){ 
		ans = add(ans, Mod + mul(op, power(2, tot) - 1));
		return;
	}
	dfs(u + 1, (tot * (cnt[u] + 1)) % (Mod-1), op);
	dfs(u + 1, (tot * cnt[u]) % (Mod-1), mul(op, -2));
	if(cnt[u] > 1) dfs(u + 1, (tot * (cnt[u] - 1)) % (Mod-1), op);
}
int main(){
	scanf("%lld", &m); prework();
	for(int i = 1; i <= tot, prim[i] * prim[i] <= m; i++){
		if(m % prim[i] == 0){ k++;
			while(m % prim[i] == 0) m /= prim[i], cnt[k]++;
		}
	} if(m != 1) cnt[++k] = 1; dfs(1, 1, 1); cout << ans; return 0;
}

T2

设最后选的个数为 ti,那么当 \sum c_i-t_i[t_i<c_i]- \sum(t_i-c_i)/4[t_i>=c_i] >0 就还不能结束

于是我们可以定义状态 f_{i,j,k} 表示选到第 i 个,共选了 j 个,上面式子为 k 的概率

我们记 k > 0 也就是还不能换的状态为合法状态

到达终止状态的期望可以看做经过的合法状态的期望次数,也就是每个合法状态的概率相加

因为没有考虑顺序,需要乘 \frac{(\sum t_i)!}{\prod t_i!}

#include<bits/stdc++.h>
#define N 12
#define M 405
#define K 1650
using namespace std;
typedef long long ll;
const int Mod = 1000000007;
ll add(ll a, ll b){ return (a + b >= Mod) ? a + b - Mod : a + b;}
ll mul(ll a, ll b){ return a * b % Mod;}
void Add(ll &a, ll b){ a = add(a, b);}
ll power(ll a, ll b){ ll ans = 1;
	for(;b;b>>=1){ if(b&1) ans = mul(ans, a); a = mul(a, a);}
	return ans;
}
int n, c[N]; ll p[N], f[N][K][M], tmp[K];
ll fac[K], ifac[K];
int main(){
	fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
	for(int i = 2; i <= K-10; i++) fac[i] = mul(fac[i-1], i);
	ifac[K-10] = power(fac[K-10], Mod - 2);
	for(int i = K-11; i >= 2; i--) ifac[i] = mul(ifac[i+1], i+1);
 	scanf("%d", &n); ll sum = 0;
	for(int i = 1; i <= n; i++) scanf("%lld", &p[i]), sum += p[i];
	sum = power(sum, Mod - 2); 
	int cnt = 0;
	for(int i = 1; i <= n; i++) p[i] = mul(p[i], sum), scanf("%d", &c[i]), cnt+=c[i];
	f[0][0][cnt] = 1;
	for(int i = 1; i <= n; i++){
		ll w = 1;
		for(int j = 0; j <= 1640; j++) tmp[j] = mul(w, ifac[j]), w = mul(w, p[i]);
		for(int j = 0; j <= 1640; j++){
			for(int k = 0; k <= 400; k++){
				if(f[i-1][j][k]){
					for(int l = 0; l + j <= 1640; l++){
						int g = ((l < c[i]) ? (l - c[i]) : (l - c[i]) / 4) + c[i];
						if(k <= g) break;
						Add(f[i][j + l][k - g], mul(f[i-1][j][k], tmp[l]));
					}
				}
			}
		}
	}
	ll ans = 1;
	for(int j = 1; j <= 1640; j++){
		ll sum = 0;
		for(int k = 1; k <= 400; k++){
			Add(sum, f[n][j][k]);
		} Add(ans, mul(sum, fac[j]));
	} cout << ans; return 0;
}

 


T3

啊好后悔考场没有静下心来推,其实并不难,发现我们要最大化

\sum_{i=1}^n\sum_{j=1}^n(x_i+vx_{i}-x_j-vx_j)^2=\sum_{i=1}^n\sum_{j=1}^n(x_i+-x_j)^2+\sum_{i=1}^n\sum_{j=1}^n(vx_{i}-vx _j) ^2+2\sum_{i=1}^n\sum_{j=1}^n(x_i-x_j)(vx_{i}-vx_j)

前面两项是常数,考虑最后一个

\sum_{i=1}^n\sum_{j=1}^n x_i*vx_i+x_j*vx_j-x_j*vx_i-x_i*vx_j

发现后面两个也是常数项

于是最大化 \sum x_i*vx_i, y 也同理,写一个最大匹配就可以了

此题卡费用流并且我不会KM, 于是咕咕咕

#include<bits/stdc++.h>
#define N 600050
#define M 505
using namespace std;
typedef long long ll;
int n, st, ed; ll x[M], y[M], vx[M], vy[M];
int first[N], nxt[N], to[N], w[N]; ll c[N]; int tot = 1;
void add(int x, int y, int z, int v){
	nxt[++tot] = first[x], first[x] = tot, to[tot] = y, w[tot] = z, c[tot] = v;
	nxt[++tot] = first[y], first[y] = tot, to[tot] = x, w[tot] = 0, c[tot] = -v;
}
ll dis[N]; bool vis[N];
int from[N], froms[N];
bool spfa(){
	queue<int> q; q.push(st);
	for(int i = 0; i <= ed; i++) dis[i] = 1e15, vis[i] = 0;
	dis[0] = 1;
	while(!q.empty()){
		int x = q.front(); q.pop(); vis[x] = 0;
		for(int i = first[x]; i; i = nxt[i]){
			int t = to[i]; if(w[i] && dis[t] > dis[x] + c[i]){
				froms[t] = i; from[t] = x;
				dis[t] = dis[x] + c[i]; if(!vis[t]) vis[t] = 1, q.push(t);
			}
		}
	} return dis[ed] != 1e15;
}
ll calc(){
	int flow = 1e9, u = ed;
	while(u^st) flow = min(flow, w[froms[u]]), u = from[u]; u = ed;
	while(u^st) w[froms[u]] -= flow, w[froms[u]^1] += flow, u = from[u];
	return flow;
}
ll dinic(){ ll ans = 0; while(spfa()) ans += calc() * dis[ed]; return ans;}
int main(){
	scanf("%d", &n); st = 0, ed = n * 2 + 1;
	for(int i = 1; i <= n; i++) scanf("%d%d", &x[i], &y[i]);
	for(int i = 1; i <= n; i++) scanf("%d%d", &vx[i], &vy[i]);
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			add(i, j + n, 1,  - x[i] * vx[j] - y[i] * vy[j]);
		}
	} 
	for(int i = 1; i <= n; i++) add(st, i, 1, 0), add(i + n, ed, 1, 0);
	dinic();
	puts("Yes"); 
	for(int i = 1; i <= n; i++){
		for(int e = first[i]; e; e = nxt[e]){
			if(!(e&1) && w[e^1]) cout << to[e] - n << " ";
		}
	} return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值