博主诈尸啦

虽然一轮之后就退役了但是二轮还是要去划划水呀~

然鹅学了不到一个月文化课再回来看OI的东西有一种恍如隔世的感觉,烤前感觉也没啥可复习的,就补一补去年二轮的题吧。

题目思路基本都参考自shadowice神仙Orz

Day2T1没时间做了咕咕咕

物理实验

充满毒瘤气息的计算几何题。。

首先旋转一下坐标系,那么只需要考虑两条线平行于\(y\)轴的情况。

由于题目中规定每个挡板都不和直线导轨接触,因此一定是分别分布于\(y > 0\)和\(y < 0\)两部分,我们分别维护。

现在只考虑上半部分,不难看出对于两条线段一上一下的情况,上面的线段被遮挡的部分是没有用的。同时所有的线段我们可以拆成加入和删除两个事件,首先预处理出两个事件之间的最大的sec,同时有了距离就可以算出答案。

然后双指针扫一下。

复杂度\(O(n \log n)\)

#include<bits/stdc++.h>
#define fi first
#define se second
#define LL long long
#define pb push_back
#define double long double
using namespace std;
const int MAXN = 1e6 + 10;
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
};
int N, opt[MAXN];
double x[MAXN][2], y[MAXN][2], pos[MAXN], bx, by, ex, ey, L;
double nx, val[MAXN], sec[MAXN];
struct Segment {
int id;
bool operator < (const Segment &rhs) const {
if(id == rhs.id) return 0;
int td = rhs.id;
double va = (y[id][1] - y[id][0]) / (x[id][1] - x[id][0]) * (nx - x[id][0]) + y[id][0];
double vb = (y[td][1] - y[td][0]) / (x[td][1] - x[td][0]) * (nx - x[td][0]) + y[td][0];
return abs(va) < abs(vb);
}
};
set<Segment> su, sd;
double GouGu(double x, double y) {
return sqrt(x * x + y * y);
}
int comp(int a, int b) {
return (a < 0 ? x[-a][1] : x[a][0]) < (b < 0 ? x[-b][1] : x[b][0]);
}
void init() {
nx = 0; memset(val, 0, sizeof(val));
}
void solve() {
N = read();
init();
for(int i = 1; i <= N; i++) {
x[i][0] = read(); y[i][0] = read(); x[i][1] = read(); y[i][1] = read();
}
bx = read(), by = read(); ex = read(); ey = read(); L = read();
double dx = ex - bx, dy = ey - by, dis = GouGu(dx, dy);
double bl = (bx == by) ? 0 : by - dy / dx * bx;
for(int i = 1; i <= N; i++) y[i][0] -= bl, y[i][1] -= bl;
dx /= dis; dy /= dis;//dx cos dy sin
//(x, y)
for(int i = 1; i <= N; i++) {
double px1 = x[i][0], px2 = x[i][1], py1 = y[i][0], py2 = y[i][1];
x[i][0] = dx * px1 + dy * py1; //tag
y[i][0] = dx * py1 - dy * px1;
x[i][1] = dx * px2 + dy * py2;
y[i][1] = dx * py2 - dy * px2;
if(x[i][0] > x[i][1]) swap(x[i][0], x[i][1]), swap(y[i][0], y[i][1]);
sec[i] = GouGu(x[i][1] - x[i][0], y[i][1] - y[i][0]) / (x[i][1] - x[i][0]);
}
for(int i = 1; i <= 2 * N; i++) opt[i] = (i <= N ? -i : i - N);
sort(opt + 1, opt + 2 * N + 1, comp);
for(int i = 1; i <= 2 * N; i++) {
int u;
if(opt[i] > 0) {//insert
u = opt[i];
nx = pos[i] = x[u][0];
(y[u][0] > 0 ? su : sd).insert({u});
} else {//delet
u = -opt[i];
nx = pos[i] = x[u][1];
(y[u][0] > 0 ? su : sd).erase({u});
}
if(!su.empty()) val[i] += sec[su.begin()->id];
if(!sd.empty()) val[i] += sec[sd.begin()->id];
}
for(int i = 2 * N; i >= 1; i--) val[i] = val[i- 1];
double ret = 0, rl = pos[1] - L, rr = pos[1], ans = 0;
int pl = 1, pr = 2;
while(pr <= 2 * N) {
double dl = pos[pl] - rl, dr = pos[pr] - rr;
if(dl > dr) ret += (val[pr] - val[pl]) * dr, pr++, rl += dr, rr += dr;
else if(dr > dl) ret += (val[pr] - val[pl]) * dl, pl++, rl += dl, rr += dl;
else ret += (val[pr] - val[pl]) * dl, pr++, pl++, rl += dl, rr += dl;
ans = max(ans, ret);
}
printf("%.15Lf\n", ans);
}
signed main() {
for(int T = read(); T--; solve());
return 0;
}

战略游戏

首先建出圆方树,那么答案为包含所有询问点的最小联通块大小 减去关键点个数

最小联通块大小可以转化为边的贡献最后特判LCA,将所有点按dfs序排序后算出相邻两点的dis,最后/2即可

复杂度\(O(n log n)\)

#include<bits/stdc++.h>
#define Pair pair<int, int>
#define MP(x, y) make_pair(x, y)
#define fi first
#define se second
//#define int long long
#define LL long long
#define pb push_back
#define Fin(x) {freopen(#x".in","r",stdin);}
#define Fout(x) {freopen(#x".out","w",stdout);}
using namespace std;
const int MAXN = 1e6 + 10, mod = 1e9 + 7;
const LL INF = 1e18 + 10;
const double eps = 1e-9;
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline LL sqr(A x){return 1ll * x * x;}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M, nd;
vector<int> v[MAXN], E[MAXN];
int dfn[MAXN], low[MAXN], times, st[MAXN], tp;
void tarjan(int x, int fa) {
dfn[x] = low[x] = ++times;
st[++tp] = x;
for(auto &to : v[x]) {
if(to == fa) continue;
if(!dfn[to]) {
tarjan(to, x), chmin(low[x], low[to]);
if(low[to] >= dfn[x]) {
E[++nd].pb(x); E[x].pb(nd);
do {
E[nd].pb(st[tp]); E[st[tp]].pb(nd);
}while(st[tp--] != to);
}
}
else chmin(low[x], dfn[to]); }
}
int dis[MAXN], siz[MAXN], son[MAXN], top[MAXN], dep[MAXN], ffa[MAXN];
void dfs(int x, int fa) {
siz[x] = 1; ffa[x] = fa;
for(auto &to : E[x]) {
if(to == fa) continue;
dis[to] = dis[x] + (to <= N);
dep[to] = dep[x] + 1;
dfs(to, x);
siz[x] += siz[to];
if(siz[to] > siz[son[x]]) son[x] = to;
}
}
void dfs2(int x, int topf) {
top[x] = topf; dfn[x] = ++times;
if(!son[x]) return ;
dfs2(son[x], topf);
for(auto &to : E[x]) {
if(top[to]) continue;
dfs2(to, to);
}
}
int LCA(int x, int y) {
while(top[x] ^ top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = ffa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
int Dis(int x, int y) {
return dis[x] + dis[y] - 2 * dis[LCA(x, y)];
}
int comp(int a, int b) {
return dfn[a] < dfn[b];
}
void init() {
for(int i = 1; i <= N; i++) v[i].clear();
for(int i = 1; i <= nd; i++) E[i].clear();
#define m0(x) memset(x, 0, sizeof(x))
m0(top); m0(dfn); m0(low); m0(dis); m0(dep); m0(son); m0(ffa); m0(siz); m0(dis);
#undef m0
tp = 0; times = 0; nd = 0; }
int ggg = 0;
void solve() {
N = read(); M = read();
init();
nd = N;
for(int i = 1; i <= M; i++) {
int x = read(), y = read();
v[x].pb(y); v[y].pb(x);
}
tarjan(1, 0);
dfs(1, 0);
dfs2(1, 1);
int Q = read();
for(int k = 1; k <= Q; k++) {
int num = read(); LL ans = 0;
vector<int> po;
for(int i = 1; i <= num; i++) po.pb(read());
sort(po.begin(), po.end(), comp);
for(int i = 0; i < po.size() - 1; i++) {
ans += Dis(po[i], po[i + 1]);
}
ans += Dis(po[num - 1], po[0]);
ans = ans / 2 + (LCA(po[0], po[num - 1]) <= N) - num;
cout << ans << '\n'; }
} signed main() {
for(int T = read(); T--; solve());
return 0;
}

反回文串

神仙反演Orzzzzzzzzzz

首先一个串的本质不同的轮换个数是不重叠最小循环节的长度

如果最小循环节的长度\(d\)是偶数,此时一个回文串的\(d\)种不同的轮换字符串当中恰好有两个回文串(本身一个,把前\(\frac{d}{2}\)个字符拼到后面一个)

否则\(d\)是奇数的话一定会有\(d\)个本质不同的字符串

首先考虑字符集为\(k\)的情况下回文串的数量\(g(n)\)

显然\(g(n) = k^{\lfloor\frac{n+1}{2} \rfloor}\)(固定一半)

那么设

\[\begin{cases}
h(i) = &i &(i \equiv 1 \pmod 2)\\
&\frac{i}{2} &(Otherwise)
\end{cases}

\]

设\(f(i)\)表示最小循环节为\(i\)的字符串数量,显然有

\(Ans(n) = \sum_{d|n} h(d) f(d)\)

\(f(d)\)很难直接求,但是我们可以枚举循环节得到一个等式

\[g(n) = \sum_{d|n} f(d)
\]

反演一下

\[f(n) = \sum_{d|n} \mu(d) g(\frac{n}{d})
\]

带入原来的公式

\[Ans(n) = \sum_{d|n} h(d) \sum_{k |d} \mu(k) g(\frac{d}{k})
\]

我们尝试枚举\(g\)

\[Ans(n) = \sum_{k|n} g(k) \sum_{k|d\text{且}d|n} h(d) \mu(\frac{d}{k})
\]

把\(d\)拆为\(d = d' * K\),我们去枚举新的\(d'\)

\[Ans(n) = \sum_{k|n} g(k) \sum_{d|\frac{n}{k}} h(k d) \mu(d)
\]

之前我们发现\(h\)函数有比较好的性质,这里似乎可以直接把\(d\)提出来。分析一下不难发现,只有当\(d\)是偶数且\(k\)是奇数是不能直接提。因为一个奇数不会有偶数因子,那么\(\frac{n}{k}\)一定是偶数

此时把式子中的\(k\)提出来,考虑一下\(k\sum_{d|\frac{n}{k}} h(d)\mu(d)\)的值,打一下表可以发现值总是\(0\),因为\(2\)这个因子使得\(mu\)为\(\pm 1\)的项消掉了

那么在计算这时候直接把这种情况判掉就可以

原式变为

\[Ans(n) = \sum_{k|n} g(k)h(k) \sum_{d|\frac{n}{k}} d\mu(d)
\]

然后直接对\(n\)进行Pollard-Rho分解,分解的同时可以求出后面的值,拿个map存一下。

然后dfs枚举约数直接算就行了

复杂度玄学,但是出题人把\(n\)出到\(10^{18}\)也只能这么干。。

#include<bits/stdc++.h>
#define fi first
#define se second
#define int long long
#define LL long long
#define pb push_back
using namespace std;
const int MAXN = 1e6 + 10;
const LL INF = 1e18 + 10;
int mod;
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
LL mul(LL a, LL b, int mod = mod) {
//a %= mod, b %= mod;
return ((a * b - (LL)((LL)((long double)a / mod * b + 1e-3) * mod)) % mod + mod) % mod;
}
int fp(int a, int p, int mod = mod) {
int base = 1;
while(p) {
if(p & 1) base = mul(base, a, mod);
a = mul(a, a, mod); p >>= 1;
}
return base;
}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, K;
int st, ans;
vector<int> ds;
unordered_map<LL, LL> t, vds;
const int Tn = 9;
int Cbase[11] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
bool CheckP(int p) {
if(p == 1) return 0;
for(int i = 0; i < Tn; i++) if(p == Cbase[i]) return 1;
for(int id = 0; id < Tn; id++) {
int v = Cbase[id];
int lim = 0, t = p - 1, pre = 1;
while(t && (!(t & 1))) lim++, t>>= 1; t = fp(v, t, p);
while(lim--) {
t = mul(t, t, p);
if(t == 1 && (pre != p - 1 && pre != 1)) return 0;
pre = t;
}
if(t != 1) return 0;
}
return 1;
} int rnd() {
return rand();
}
int gcd(int a, int b) {
return (!b) ? a : gcd(b, a % b);
}
int rd(int base, int mod) {
return (mul(base, base, mod) + st) % mod;
}
int myabs(int x, int y) {
return (x > y) ? x - y : y - x;
} void Rho(int x) {
if(x == 1) return ;
if(CheckP(x)) {
vds[x]++;
return ;
}
while(1) {
st = rand() % x + 1;
int v1 = rnd() % x + 1, g = gcd(x, v1);
if(g != 1 && g != x) {Rho(g); Rho(x / g); return ;}
int v2 = v1; v1 = rd(v1, x);
for(int k = 0, tr = 1; v1 - v2; v1 = rd(v1, x), k++) {
g = gcd(x, myabs(v1, v2));
if(g != 1 && g != x) {Rho(g); Rho(x / g); return ;}
if(k == tr) {v2 = v1; tr <<= 1;}
}
}
}
void Clear() {
ds.clear();
vds.clear();
ans = 0;
}
int g(int x) {
return fp(K, (x + 1) / 2);
}
int h(int x) {
return (x & 1) ? x : x / 2;
} void dfs(int n, int num, int cur, unordered_map<LL, LL>::iterator now) {
if(now == vds.end()) {
ds.pb(num);
t[num] = cur;
return ;
}
int nn = now->se, vv = now->fi, vvd = (1 - now->fi), nv = vv, nvd = vvd; auto nxt = ++now;
dfs(n + 1, num, cur, nxt);
for(int i = 1; i <= nn; i++) {
dfs(n + 1, num * nv, cur * vvd, nxt);
nv *= vv; nvd *= vvd;
}
}
void print(int x) {
if(x > 9) print(x / 10);
putchar('0' + x % 10);
}
void solve() {
Clear();
N = read(); K = read(); mod = read(); K %= mod;
Rho(N);
dfs(0, 1, 1, vds.begin());
for(auto &num: ds) {
if((num & 1) && (!((N / num) & 1))) continue;
add2(ans, mul(g(num), mul(h(num), t[N / num])));
}
print(ans); putchar('\n');
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("a.in", "r", stdin);
#endif
srand(20020113);
for(int T = read(); T--; solve());
return 0;
}

旧式题

我实在不想照着题解抄一遍公式了qwq

#include<bits/stdc++.h>
#define Pair pair<int, int>
#define MP make_pair
#define fi first
#define se second
#define LL long long const int MAXN = 2e5 + 10, mod = 1e9 + 7;
using namespace std;
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int mu[MAXN], prime[MAXN], vis[MAXN], tot, A, B, C, num, deg[MAXN];
int fa[MAXN], fb[MAXN], fc[MAXN];
vector<LL> di[MAXN];
vector<Pair> v[MAXN];//每个数的质因数分解
struct Edge {
LL u, v, w;
}E[MAXN * 10];
void GetPrime(int N) {
vis[1] = 1; mu[1] = 1;
for(int i = 2; i <= N; i++) {
if(!vis[i]) prime[++tot] = i, mu[i] = -1;
for(int j = 1; j <= tot && i * prime[j] <= N; j++) {
vis[i * prime[j]] = 1;
if(i % prime[j]) mu[i * prime[j]] = -mu[i];
else {mu[i * prime[j]] = 0; break;}
}
}
for(int i = 1; i <= tot; i++)
for(int j = 1; j * prime[i] <= N; j++)
di[j * prime[i]].push_back(prime[i]); } void Get(int *a, int N, int X) {
for(int i = 1; i <= N; i++)
for(int j = i; j <= N; j += i) a[i] += X / j;
}
LL lcm(int a, int b) {
return 1ll * a / __gcd(a, b) * b;
}
void init() {
memset(fa, 0, sizeof(fa));
memset(fb, 0, sizeof(fb));
memset(fc, 0, sizeof(fc));
memset(deg, 0, sizeof(deg));
num = 0;
for(int i = 1; i <= A; i++) v[i].clear();
}
void Build() {
for(int w = 1; w <= A; w++) {//lcm(u, v) = w;
if(!mu[w]) continue;
int n = di[w].size();
//for(auto x : di[w]) printf("%d ", x); puts("");
for(int sta = 0; sta < (1 << n); sta++) {
LL i = 1;
for(int b = 0; b < n; b++)
if(sta >> b & 1) i *= di[w][b];
for(int s = sta; ; s = sta & (s - 1)) {//tag
LL g = 1;
for(int b = 0; b < n; b++)
if(s >> b & 1)
g *= di[w][b];
int j = w * g / i;
if(i < j) E[++num] = {i, j, w};// printf("%d\n", num);
if(!s) break;
}
}
}
} LL fuck(int x, int y, int w) {
if(mu[x] == 1)
return add(add(mul(mul(fa[w], fb[w]), fc[y]), mul(mul(fa[w], fb[y]), fc[w])), mul(mul(fa[y], fb[w]), fc[w]));
else
return (-add(add(mul(mul(fa[w], fb[w]), fc[y]), mul(mul(fa[w], fb[y]), fc[w])), mul(mul(fa[y], fb[w]), fc[w])) + mod) % mod;
} LL calc() {
// for(int i = 1; i <= A; i++) for(auto &x : v[i])printf("%d %d %d\n", i, x.fi, x.se);
for(int i = 1; i <= num; i++) {
int x = E[i].u, y = E[i].v;
if(deg[x] > deg[y]) swap(x, y);
v[y].push_back(MP(x, E[i].w));
}
LL ans = 0;
for(int a = 1; a <= A; a++) {
for(auto &t1 : v[a]) {
LL b = t1.fi, w1 = t1.se;
for(auto &t2 : v[b]) {
LL c = t2.fi, w2 = t2.se, xi = mu[a] * mu[b] * mu[c];
LL w3 = lcm(a, c);
if(w3 > A) continue;
if(xi == 1) {
add2(ans, mul(mul(fa[w1], fb[w2]), fc[w3]));
add2(ans, mul(mul(fa[w1], fb[w3]), fc[w2]));
add2(ans, mul(mul(fa[w2], fb[w1]), fc[w3]));
add2(ans, mul(mul(fa[w2], fb[w3]), fc[w1]));
add2(ans, mul(mul(fa[w3], fb[w1]), fc[w2]));
add2(ans, mul(mul(fa[w3], fb[w2]), fc[w1]));
} else if(xi == -1) {
add2(ans, mul(mul(-fa[w1], fb[w2]), fc[w3]));
add2(ans, mul(mul(-fa[w1], fb[w3]), fc[w2]));
add2(ans, mul(mul(-fa[w2], fb[w1]), fc[w3]));
add2(ans, mul(mul(-fa[w2], fb[w3]), fc[w1]));
add2(ans, mul(mul(-fa[w3], fb[w1]), fc[w2]));
add2(ans, mul(mul(-fa[w3], fb[w2]), fc[w1]));
}
// cout << ans << endl;
}
}
} for(int i = 1; i <= num; i++) {//有两个一样
add2(ans, fuck(E[i].u, E[i].v, E[i].w));
add2(ans, fuck(E[i].v, E[i].u, E[i].w));
}
for(int i = 1; i <= C; i++) {//全都一样
if(mu[i] == 1) add2(ans, mul(mul(fa[i], fb[i]), fc[i]));
else if(mu[i] == -1) add2(ans, -mul(mul(fa[i], fb[i]), fc[i]) + mod);
} return ans;
}
void solve() {
init();
A = read(); B = read(); C = read();
if(A < B) swap(A, B); if(C > B) swap(B, C); if(A < B) swap(A, B);
Get(fa, A, A); Get(fb, A, B); Get(fc, A, C);
Build();
cout << calc() << '\n';
}
signed main() {
GetPrime(2e5);
for(int T = read(); T; T--, solve());
return 0;
}

荣誉称号

每个位置\(x\)向\(\frac{x}{2}\)连边最终会得到一棵完全二叉树

题目转化为:给出一个有点权的树,对于每个点可以花费\(b_i\)的代价使点权增加\(1\),问使得所有长度为\(k + 1\)的链的点权和\(\% M\)均为\(0\)的最小花费

首先考虑序列的情况,稍加归纳后不难得到\(a_i \equiv a_{i + K + 1} \pmod M\)

放到树上话那么最终一个点的权值一定和它的\(K+1\)级祖先相同,因此对于前\(2^{k}\)个点,我们\(O(nm)\)预处理出\(w[x][y]\)表示\(x\)的点为\(y\)时,所有能被它限制的点的代价

现在只需要考虑前\(2^{k+1}-1\)个点,首先把标号\(< 2^k\)的叶子节点删掉,对于剩下的点的限制条件变为所有叶子节点到根的路径和\(\% M =0\)。那么设\(f[i][j]\)表示以\(i\)为根的子树,到所有叶子节点的权值\(\%M = j\)的最小代价,转移的时候暴力枚举该点的取值。

复杂度\(O(nm + 2^k m^2)\)可以拿到70分

考虑\(w\)的预处理,std在这里用了一个等差数列,实际上不用这么麻烦,因为\(a[i]\)取值只有\(200\),直接对值域暴力就行

复杂度\(O(n + 2^k m^2)\)

#include<bits/stdc++.h>
#define Pair pair<int, int>
#define MP(x, y) make_pair(x, y)
#define fi first
#define se second
//#define int long long
#define LL long long
#define pb push_back
#define Fin(x) {freopen(#x".in","r",stdin);}
#define Fout(x) {freopen(#x".out","w",stdout);}
using namespace std;
const int MAXN = 1e7 + 10, mod = 1e9 + 7;
const LL INF = 1e18 + 10;
const double eps = 1e-9;
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline LL sqr(A x){return 1ll * x * x;}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int ch(int x, int l, int r) {
return x >= l && x <= r;
}
int N, K, M, P, a[MAXN], mx[MAXN], n, jump, fa[MAXN], b[MAXN];
vector<int> bel[MAXN];
unsigned int SA, SB, SC;int p, A, B;
unsigned int rng61(){
SA ^= SA << 16;
SA ^= SA >> 5;
SA ^= SA << 1;
unsigned int t = SA;
SA = SB;
SB = SC;
SC ^= t ^ SA;
return SC;
}
void gen(){
N = read(); K = read(); M = read(); P = read(); SA = read(); SB = read(); SC = read(); A = read(); B = read();
for(int i = 1; i <= P; i++) a[i] = read() % M, b[i] = read();
for(int i = P + 1; i <= N; i++){
a[i] = rng61() % A + 1;
a[i] %= M;
b[i] = rng61() % B + 1;
}
} LL w[(1 << 12) - 1][201];//w[i][j] 当i为j时,所有受i限制的点的代价
LL f[(1 << 12) - 1][201], num[211]; void dfs(int x, int dep) {
mx[x] = dep;
if(dep > K + 1) bel[fa[x]].pb(x);
int base = 2 * x;
for(int i = 0; i <= 1; i++) {
int to = 2 * x + i; if(to > N) continue;
dfs(to, dep + 1);
chmax(mx[x], mx[to]);
}
}
LL get(int val, LL target, LL inc) {//在%M意义下把val变为target的最小花费
if(target >= val) return 1l * (target - val) * inc;
return 1ll * ((M - val) + target) * inc;
}
void dfs2(int x) {
if(x > n || mx[x] <= K) return ;
if(x >= (1 << K)) {//叶节点
for(int i = 0; i < M; i++) f[x][i] = w[x][i];
return ;
}
for(int i = 0; i < 2; i++) if(2 * x + i <= n) dfs2(2 * x + i);
for(int i = 0; i < M; i++) {//与叶子节点的路径和%M = j
f[x][i] = INF;
for(int j = 0; j < M; j++) {//该节点的增量
LL sv = 0;
for(int gg = 0; gg < 2; gg++) {
int to = 2 * x + gg;
if(to <= n)
sv += f[to][(i - a[x] - j + 2 * M) % M];
}
chmin(f[x][i], sv + w[x][(a[x] + j) % M]);
}
}
} void solve() {
gen();
memset(f, 0, sizeof(f));
memset(w, 0, sizeof(w));
jump = 1; n = (1 << (K + 1)) - 1;
for(int i = 1; i <= K + 1; i++) jump *= 2;
for(int i = 1; i <= N; i++) {
bel[i].clear();
} for(int i = 1; i <= N; i++) fa[i] = (i <= n ? i : fa[i / jump]);
dfs(1, 1); for(int i = 1; i < (1 << (K + 1)); i++) {
memset(num, 0, sizeof(num));
for(auto &son: bel[i]) num[a[son]] += b[son];
for(int j = 0; j < M; j++) {
w[i][j] += get(a[i], j, b[i]);
for(int k = 0; k < M; k++) w[i][j] += get(k, j, num[k]);
}
}
dfs2(1);
cout << f[1][0] << '\n';
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("title-task3.in", "r", stdin);
#endif
for(int T = read(); T--; solve());
return 0;
}

SDOI 2018二轮题解(除Day2T1)的更多相关文章

  1. SDOI 二轮垫底鸡

    SDOI 二轮垫底鸡 day0 准备爆零 没啥好准备考试的,12.00出发,试机敲抄个ntt,在宾馆不知道颓啥. day1 爆零爬山 T1noip的题目也放到省选上. 第一档线段树?肯定不写,直接上1 ...

  2. SDOI 2018划水记

    Day0 最后一天啦,此时不颓更待何时? 上午10:15坐车从gryz出发,在一路颓废中到了农大 不得不说,农大的宾馆真的好高档啊,壁橱里面居然有保险柜!电视柜厨子里居然有冰箱!!冰箱里居然有饮料!! ...

  3. SDOI 2018 R2 游记

    一篇真正的“游记”. DAY -3 下午: 今天老师批准了我去省选划水的请假要求. 批准之后感觉学习非常有动力,顺便忽悠别的同学和我一起去,然而wzx是唯一一个表示可以考虑一下的同学,其他同学直接一口 ...

  4. 2017 山东二轮集训 Day7 国王

    2017 山东二轮集训 Day7 国王 题目大意 给定一棵树,每个点有黑白两种颜色,定义一条简单路径合法当且仅当路径上所有点黑色与白色数量相等,求有多少非空区间 \([L,R]\) ,使得所有编号 \ ...

  5. ZJOI2019二轮游记

    Postscript 这个彩笔的省选随心游被中考实验考试坑掉了 所以前两天都一直脱离部队,第一天讲课完了才有的过去 一轮凉了那么二轮翻盘?翻车预定.之后还有上海的ACM没有CXR神仙的ACM窝怎么打啊 ...

  6. SDOI2018 二轮培训划水记

    \(\mathcal{Day -1}\) 嗯,虽然说\(rqy\)看我们这么懵O,并不建议我们去掺和这种神仙打架,但是为了逃文化课学习OI并参观膜拜各路神仙,我毅然决然地选择去参加这次培训-- 这次一 ...

  7. Noip2011瑞士轮题解

    题目背景 在双人对决的竞技性比赛.如乒乓球.羽毛球.国际象棋中.最常见的赛制是淘汰赛和循环赛.前者的特点是比赛场数少.每场都紧张刺激,但偶然性较高.后者的特点是较为公平,偶然性较低,但比赛过程往往十分 ...

  8. 「SDOI 2018」反回文串

    题目大意: 求字符集大小为$k$长度为$n$的经循环移位后为回文串的数量. 题解: 这题是D1里最神的吧 考虑一个长度为$n$回文串,将其循环移位后所有的串都是满足要求的串. 但是显然这样计算会算重. ...

  9. 「SDOI 2018」战略游戏

    题目大意: 给一个$G=(V,E)$,满足$|V|=n$,$|E|=m$,且保证图联通,有Q个询问,每组询问有s个点,求图中有多少点满足:将其删去后,这s个点中存在一对点集$(a,b)$不联通且删去点 ...

随机推荐

  1. 开源监控系统中 Zabbix 和 Nagios 哪个更好?

    监控平台的话,各有优劣,但基本都可以满足需求.等达到一定监控指标后,发现,最困难的是监控项目的管理. CMDB中小规模(服务器<=1k):Zabbix大规模(1k>=服务器<=10k ...

  2. syslog-ng 配置(tcp协议)

    一.概况 两台服务器,都安装syslog-ng,一台服务端,一台客户端: server:192.168.209.19 client:192.168.209.18 二.安装 采用yum安装,执行: yu ...

  3. SimpliciTI协议地址分配

    1.多个ED节点和AP正确连接后,AP都会给ED分配一个相应的地址.当某个ED出现意外,比如电源问题,和AP断开连接,AP并不将该ED节点的地址消除.当该ED恢复正常,重新申请加入网络时,AP会检测该 ...

  4. (六)编写基类BaseDao

    在action中继承了ActionSupport和其它一些公共属性,如selectedRow等:可能以后还会产生更多公共的内容,所以应该把这些共有的抽取出来,放入到一个基本action中,我们命名为B ...

  5. Django中ORM外键和表的关系(Django编程-4)

    外键 在MySQL中,表有两种引擎,一种是InnoDB,另外一种是myisam.如果使用的是InnoDB引擎,是支持外键约束的.外键的存在使得ORM框架在处理表关系的时候异常的强大.因此这里我们首先来 ...

  6. ansible无网络安装openstack(Newton)

    概要 apt使用本地源,pip使用本地源 网络环境 物理机环境 网络名 网络地址 VLAN br-ex 192.168.200.250/24 90 br-mgmt 92.0.0.100/24 92 a ...

  7. web前端篇:CSS使用,样式表特征,选择器

    目录 web前端篇:CSS使用,样式表特征,选择器 1.CSS介绍 2.CSS使用 3.样式表特征 4.CSS选择器 5.选择器的优先级 6.练习题: web前端篇:CSS使用,样式表特征,选择器 1 ...

  8. jdk及tomcat的安装

    Tomcat和JDK安装指南 1  JDK的安装 要运行JAVA程序,必须安装JDK(JAVA 开发包)的支持. 1.1  安装 1.J2SDK的安装比较简单,在安装盘目录下寻找“JDK安装程序”文件 ...

  9. NOIp知识集合 By cellur925

    基本算法 快速幂 ll ksm(ll a,ll b) { ll ans=; while(b) { ) ans=ans*a%p; b>>=; a=a*a%p; } return ans; } ...

  10. Java 多线程高并发编程 笔记(一)

    本篇文章主要是总结Java多线程/高并发编程的知识点,由浅入深,仅作自己的学习笔记,部分侵删. 一 . 基础知识点 1. 进程于线程的概念 2.线程创建的两种方式 注:public void run( ...