省选模拟 19/08/11

Posted qq62c30ac77b2a7

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了省选模拟 19/08/11相关的知识,希望对你有一定的参考价值。

​T1​​ 

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

考虑 gcd,lcm 的另一种形式,不妨设 省选模拟

就是 对于每一个质因子,选出来的次数 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,那么当  就还不能结束

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

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

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

因为没有考虑顺序,需要乘 省选模拟

#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​

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

省选模拟

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

省选模拟

发现后面两个也是常数项

于是最大化 省选模拟, 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;

 


以上是关于省选模拟 19/08/11的主要内容,如果未能解决你的问题,请参考以下文章

2018.3.10 省选模拟赛

省选模拟38

[考试反思]0220省选模拟27:怪异

[考试反思]0114省选模拟7:迷离

2018.3.25 省选模拟一 day2 总结

ZROI 19.08.11模拟赛