博主诈尸啦

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

然鹅学了不到一个月文化课再回来看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. bzoj 3872 [Poi2014]Ant colony——二分答案

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3872 可以倒推出每个叶子节点可以接受的值域.然后每个叶子二分有多少个区间符合即可. 注意一开 ...

  2. The specified named connection is either not found in the configuration, not intended to be used

    今天用EF遇到一个问题, The specified named connection is either not found in the configuration, not intended t ...

  3. HDU1540(线段树统计连续长度)

    ---恢复内容开始--- Tunnel Warfare Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d &am ...

  4. msfvenom 摄像头

    4.13 莫名其妙的心情不好 又回到了那个不想打游戏不想聊天不想说话的日子. 不用想.vm——>kali 很早以前看过用msfvenom生成木马的文章.然后……然后我的浏览器就崩溃了.Firef ...

  5. Tomcat的目录结构详解

    转自:https://blog.csdn.net/u012661010/article/details/73381599

  6. 【243】◀▶IEW-Unit08

    Unit 8 Environment I. 不定式(to do)在雅思写作中的运用 1)名词 • 主语(句首) To protect the environment is everyone's dut ...

  7. Attribute meta-data#android.support.VERSION@value value=(25.4.0) from AndroidManifest.xml:25:13-35 is also present at AndroidManifest.xml:28:13-35 value=(26.1.0).

    Android Studio 编译项目的时候报错 Merging Errors: Error: Attribute meta-data#android.support.VERSION@value va ...

  8. centos6.5安装sublime Text3破解版

    安装后的效果图: 在csdn上找到了一个破解版. http://download.csdn.net/download/phpscott2/5356561 安装后,能够运行,但每次打开都提示没有安装py ...

  9. HDU 1532 Drainage Ditches (网络流)

    A - Drainage Ditches Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64 ...

  10. 微信小程序运行机制

    对于扫描接口B生成的带参小程序码的问题: (1)线上版本 扫描不同带参的小程序码会重新执行小程序的整个注册程序生命周期(详细生命周期函数见官方文档), (2)扫描相同的二维码的时候,目前微信官方给出的 ...