A. 直接pow,代码略
B
分子分母分开处理
\(a/b\)转移到\(\frac{\frac{a}{b}+\frac{b}{a}}{2} = \frac{a^2+b^2}{2ab}\)
然后\(a'=a^2+b^2, b'=2ab\)所以\(a'+b'=(a+b)^2, a'-b' = (a-b)^2\)
可以找规律完成递推
%:pragma GCC optimize(3) #include<bits/stdc++.h> using namespace std; const int L = 1E5+10, R = 500000002; #define int ll typedef long long ll; const ll MOD = 1e9+7, PHI = MOD-1; ll qpow(ll a, ll b,ll mod){ ll ret = 1; for(;b;b>>=1){ if(b & 1) ret = ret * a %mod; a = a * a % mod; } return ret; } ll inv(ll x){ return qpow(x, MOD-2, MOD); } ll get(ll a, ll b){ if(b == 0) return a; ll x = (a + 1) * inv(2) % MOD, y = (a - 1) * inv(2) % MOD; ll p = qpow(x, (qpow(2, b, PHI)), MOD) , q = qpow(y, qpow(2, b, PHI),MOD); return (p + q)%MOD * inv(p - q)%MOD; } void solve(){ ll x, n; cin >> x >> n; --n; cout << (get(x, n)+ MOD)%MOD << endl; } signed main(){ ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int T; cin >> T; while(T--){ solve(); } }
C
非常有趣
我们的目的是把每个点的最小alpha求出来
如何求?一条边有两个方向,一条边和一个方向可以决定一个贡献
我们把有向边定向,然后求每条有向边的alpha
每条有向边\((u,v)\)可以对\(u\)的子树产生贡献
对子树贡献可以用线段树区间取\(max\)维护
线段树每个叶子\(u\)表示\(u\)为根时的最小alpha
#include<bits/stdc++.h> using namespace std; typedef long double ld; const int N = 1e5 + 10, TR = 4 * N, E = 2 * N; const ld eps = 1e-14; int n,k, q; struct segment_tree{ struct node{ ld laz; }tree[TR]; void update(int rt, ld val){ tree[rt].laz = max(tree[rt].laz, val); } void modify(int rt,int l, int r, int s, int t, ld val){ if(s > t) return; if(s <= l && r <= t){ tree[rt].laz = max(tree[rt].laz, val); return; } int mid = (l + r) >> 1; if(s <= mid) modify(rt<<1, l, mid, s ,t, val); if(t > mid) modify(rt<<1|1, mid+ 1, r, s ,t, val); } ld query(int rt, int l, int r, int s){ ld ret = tree[rt].laz; if(l >= r){ return ret; } int mid = (l + r) >> 1; if(s <= mid) return max(ret, query(rt<<1, l, mid, s)); else return max(ret, query(rt<<1|1, mid + 1, r, s)); } }segt; struct graph{ struct edge{ int nxt, to; }e[E]; graph(){ elen = 1; } int elen, head[N]; void inse(int frm, int to){ e[++elen] = {head[frm], to}; head[frm] = elen; ++deg[to]; } void insf(int u, int v){ inse(u, v),inse(v, u); } int fat[N]; int siz[N], deg[N]; int son1[N], son2[N]; int dfn[N], tim; ld val[E]; void dfs1(int u){ siz[u] = 1; for(int i = head[u]; i; i = e[i].nxt){ int v = e[i].to; if(v == fat[u]) continue; fat[v] = u; dfs1(v); siz[u] += siz[v]; if(siz[v] > siz[son1[u]]){ son2[u] = son1[u], son1[u] = v; }else if(siz[v] > siz[son2[u]]){ son2[u] = v; } } } void dfs2(int u){ for(int i = head[u]; i;i = e[i].nxt){ int v = e[i].to; if(v == fat[u]) continue; val[i] = deg[v] <= 2 ? 0 : ld(siz[son1[v]]) /siz[v]; dfs2(v); } for(int j = head[u]; j;j= e[j].nxt){ int i = (j ^ 1); int v = e[j].to; if(v == fat[u]) continue; int mxp = (v == son1[u]) ? son2[u] : son1[u]; int mxs = max( n - siz[u], siz[mxp]); val[i] = deg[u] <= 2 ? 0 :ld(mxs) / (n - siz[v]); } } void dfs3(int u){ dfn[u] = ++tim; for(int i = head[u]; i; i= e[i].nxt){ int v = e[i].to; if(v == fat[u]) continue; dfs3(v); } } void dfs4(int u){ for(int i = head[u]; i;i = e[i].nxt){ int v = e[i].to; if(v == fat[u]) continue; int j = i ^ 1; segt.modify(1, 1, n, dfn[v], dfn[v] + siz[v] - 1, val[j]); dfs4(v); } for(int i = head[u]; i;i = e[i].nxt){ int v = e[i].to; if(v == fat[u]) continue; segt.modify(1, 1, n, 1, dfn[v] - 1, val[i]); segt.modify(1, 1 ,n, dfn[v] + siz[v], n ,val[i]); } } }G; ld wei[N]; int main(){ ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n >> k; for(int i = 1; i < n; ++i){ int u, v; cin >> u >> v; G.insf(u, v); } G.dfs1(1); G.dfs2(1); G.dfs3(1); G.dfs4(1); for(int i = 1; i <= n; ++i){ wei[i] = segt.query(1, 1, n, G.dfn[i]); } for(int i = 1; i <= n; ++i){ if(G.deg[i] >= 2){ int msiz = max(G.siz[G.son1[i]], n - G.siz[i]); wei[i] = max(wei[i], (ld)1.0 * msiz / n); } } sort(wei + 1, wei + 1 + n); cin >> q; int las = 0; for(int i = 1; i <= q ; ++i){ int u , v; cin >> u >> v; u = u xor (las * k), v = v xor(las * k); ld key = ld(u)/v; las = (upper_bound(wei + 1, wei + 1 + n, key + eps) - wei - 1); cout << las << endl; } return 0; }
D
发现价钱和天数是等价的,于是我们设工厂的两个关建值为\(a, b\)
商店为\(c,d\)
\(a,b\)越小越好,\(c,d\)越大越好
我们分别排序,并且去掉一定不可能产生贡献的点(若\(a, b\)均比另一个点大)
接下来发现有决策单调性,分治即可
证明:设\(u\)为商店,\(i,j\)为两个工厂\(i<j\),若\(j\)比\(i\)优,则
\((c_u - a_i) * (d_u - b_i) < (c_u - a_j) * (d_u - b_j)\)
展开后移项,得
\(d_u(a_j-a_i) + a_jb_j< c_u(b_i-b_j) + a_kb_k\)
因为\(i<j\),所以\(a_i-a_i > 0\) ,\(b_i - b_j>0\)
又因为对\(v > u\), \(d_v < d_u, c_v < c_u\)所以\(j仍然比\)i$优
#pragma GCC optimize(3) #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5e5+10; struct t_a{ int a, b; bool operator < (const t_a &rhs) const{ return tie(a, b) < tie(rhs.a, rhs.b); } }x[N],t1[N]; struct t_b{ int c, d; bool operator <(const t_b & rhs)const{ return tie(d, c) > tie(rhs.d, rhs.c); } }y[N],t2[N]; ll ans = 0; ll calc(t_a a, t_b b){ if(b.c - a.a < 0 || b.d - a.b < 0) return 0; return 1ll * (b.c - a.a) * (b.d- a.b); } void solve(int l, int r, int s, int t){ if(l > r || s > t) return; int mid = (l + r) >> 1; int pos = s; for(int i = s + 1; i <= t; ++i){ if(calc(t1[i], t2[mid]) >= calc(t1[pos], t2[mid])){ pos = i; } } ans = max(ans, calc(t1[pos], t2[mid])); solve(l, mid - 1, s, pos); solve(mid + 1, r, pos, t); } int m, n; int main(){ ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> m >> n; for(int i = 1; i <= m; ++i){ cin >> x[i].a >> x[i].b; } for(int i = 1; i <= n; ++i){ cin >> y[i].c >> y[i].d; } sort(x + 1, x + m + 1); sort(y + 1 ,y + n + 1); int c1 = 0, c2 = 0; t1[++c1] = x[1]; t2[++c2] = y[1]; for(int i = 2; i <= m; ++i){ if(t1[c1].b <= x[i].b) continue; t1[++c1] = x[i]; } for(int i = 2; i <= n; ++i){ if(t2[c2].c >= y[i].c) continue; t2[++c2] = y[i]; } m = c1, n = c2; for(int i = 1; i <= n; ++i){ int pos = lower_bound(t1 + 1, t1 + 1 + m, t_a{t2[i].c, -1}) - t1 - 1; if(pos == 0 || t1[pos].b >= t2[i].d){ t2[i].c = t2[i].d = -1; } } c2 = 0; for(int i = 1; i <= n; ++i){ if(t2[i].c == -1) continue; y[++c2] = t2[i]; } n = c2; memcpy(t2, y, sizeof(t2)); solve(1, n, 1, m); cout << ans << endl; return 0; }