2023.01.12 模拟赛小结
2023.01.12 模拟赛小结
更好的阅读体验戳此进入
赛时思路
T1
求随机的
最开始的思路是 int
范围内,但是
关于具体的证明,准备在补完 ABC266Ex,写完可持久化文艺平衡树和序列加强版之后再去补生成函数相关内容。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
int N;
// ld dp[2][1100][1100];
// ll dp[1100];
// ll tot[1100];
// ld dp[1100];
int main(){
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
N = read();
// dp[1][1][0] = 1.0;
// for(int i = 2; i <= N; ++i){
// ll base(0);
// for(int j = 0; j <= i; ++j)for(int k = 0; k <= i; ++k)if(dp[!(i & 1)][j][k])base += 2 * j + k;
// for(int j = 0; j <= i; ++j){
// for(int k = 0; k <= i; ++k){
// dp[i & 1][j][k] = 0.0;
// if(k - 1 >= 0)dp[i & 1][j][k] += (2.0 * j / base) * dp[!(i & 1)][j][k - 1],
// printf("upd i = %d, j = %d, k = %d, from %.5Lf\n", i, j, k, dp[!(i & 1)][j][k - 1]);
// if(j - 1 >= 0)dp[i & 1][j][k] += ((k + 1.0) / base) * dp[!(i & 1)][j - 1][k + 1];
// }
// }
// }
// ld ans(0.0);
// for(int j = 0; j <= N; ++j)for(int k = 0; k <= N; ++k)ans += dp[N & 1][j][k] * j;
// printf("%.9Lf\n", ans);
// dp[1] = 1.0;
// for(int i = 2; i <= N; ++i)
// for(int j = 0; j <= i; ++j)
// if(i - j - 1 >= 0)
// dp[i] += (dp[j] + dp[i - j - 1])
// printf("%.9Lf\n", (ld)((__float128)dp[N] / tot[N]));
// dp[1] = 1, tot[0] = tot[1] = 1;
// for(int i = 2; i <= N; ++i)
// for(int j = 0; j <= i; ++j)
// if(i - j - 1 >= 0)
// dp[i] += dp[j] * tot[i - j - 1] + dp[i - j - 1] * tot[j],
// tot[i] += tot[j] * tot[i - j - 1];
// for(int i = 0; i <= N; ++i)printf("dp is %lld, tot is %lld\n", dp[i], tot[i]);
printf("%.10Lf\n", (((ld)N * N + N) / (4 * N - 2)));
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
T2
给定
以前没见过这种套路,想了一会能想到的只有离线下来 Tarjan 求 LCA,这样最终复杂度是
然后最后耗时
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
struct Edge{
Edge* nxt;
int to;
OPNEW;
}ed[21000];
ROPNEW;
Edge* head[11000];
int N, M;
int cnt(0);
int dep[11000];
ll ans[11000];
struct Query{short p; int idx;};
basic_string < Query > qs[11000];
bitset < 11000 > vis;
int lca[110000000];
struct Q{int l, r, z;}q[11000];
class UnionFind{
private:
int fa[11000];
public:
UnionFind(void){for(int i = 1; i <= 10000; ++i)fa[i] = i;}
int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}
void Union(int x, int y){fa[Find(y)] = Find(x);}
}uf;
void dfs(int p = 1, int fa = 0){
dep[p] = dep[fa] + 1;
for(auto i = head[p]; i; i = i->nxt)if(SON != fa)dfs(SON, p);
}
void Tarjan(int p = 1, int fa = 0){
vis[p] = true;
for(auto i = head[p]; i; i = i->nxt)if(SON != fa)Tarjan(SON, p), uf.Union(p, SON);
for(auto q : qs[p])if(vis[q.p])lca[q.idx] = uf.Find(q.p);
}
int main(){
freopen("eert.in", "r", stdin);
freopen("eert.out", "w", stdout);
N = read(), M = read();
for(int i = 2; i <= N; ++i){
int s = i, t = read();
head[s] = new Edge{head[s], t};
head[t] = new Edge{head[t], s};
}dfs();
for(int i = 1; i <= M; ++i){
q[i].l = read(), q[i].r = read(), q[i].z = read();
for(int p = q[i].l; p <= q[i].r; ++p)qs[q[i].z] += Query{(short)p, ++cnt}, qs[p] += Query{(short)q[i].z, cnt};
}Tarjan();
int cur(0);
for(int i = 1; i <= M; ++i){
for(int ccnt = cur + 1; ccnt <= cur + (q[i].r - q[i].l + 1); ++ccnt)ans[i] += dep[lca[ccnt]];
cur += (q[i].r - q[i].l + 1);
}
for(int i = 1; i <= M; ++i)printf("%lld\n", ans[i]);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
T3
LG-P6621 [省选联考 2020 A 卷] 魔法商店。
及其阴间的保序回归,经典 @sssmzy 组的模拟赛中的科技题,感觉暴力都不是很可写,跳了跳了。
正解
T1
上面提过了,long long
。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
int N;
int main(){
N = read();
printf("%.10Lf\n", (((ld)N * N + N) / (4ll * N - 2)));
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
T2
正解看到之后会发现非常显然,但是如果要直接想却不太容易想到,应该算是一种套路。
考虑对区间
不难想到 树剖 + 线段树 维护,这样的复杂度是
于是考虑将询问转成差分形式,即拆成
需要注意本题点的编号的问题。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define MOD (201314)
template < typename T = int >
inline T read(void);
struct Edge{
Edge* nxt;
int to;
OPNEW;
}ed[110000];
ROPNEW;
Edge* head[51000];
int N, M;
struct Query{
int endp;
int val;
int idx;
bool flag; //false -> [1, l - 1], true -> [1, r]
};
basic_string < Query > qs;
ll ans[51000];
class SegTree{
private:
ll tr[51000 << 2];
ll lz[51000 << 2];
#define LS (p << 1)
#define RS (LS | 1)
#define MID ((gl + gr) >> 1)
public:
void Pushup(int p){tr[p] = (tr[LS] + tr[RS]) % MOD;}
void Pushdown(int p, int gl, int gr){
if(!lz[p])return;
(lz[LS] += lz[p]) %= MOD, (lz[RS] += lz[p]) %= MOD;
(tr[LS] += lz[p] * (MID - gl + 1) % MOD) %= MOD, (tr[RS] += lz[p] * (gr - (MID + 1) + 1) % MOD) %= MOD;
lz[p] = 0;
}
ll Query(int l, int r, int p = 1, int gl = 1, int gr = N){
if(l <= gl && gr <= r)return tr[p];
if(gr < l || r < gl)return 0;
Pushdown(p, gl, gr);
return (Query(l, r, LS, gl, MID) + Query(l, r, RS, MID + 1, gr)) % MOD;
}
void Modify(int l, int r, int v = 1, int p = 1, int gl = 1, int gr = N){
if(l <= gl && gr <= r)return (tr[p] += (gr - gl + 1) * v % MOD) %= MOD, (lz[p] += v) %= MOD, void();
Pushdown(p, gl, gr);
if(l <= MID)Modify(l, r, v, LS, gl, MID);
if(MID + 1 <= r)Modify(l, r, v, RS, MID + 1, gr);
Pushup(p);
}
}st;
int dep[51000], dfn[51000], fa[51000], hson[51000], siz[51000], top[51000], idx[51000];
void dfs_pre(int p = 1, int ffa = 0){
fa[p] = ffa;
dep[p] = dep[ffa] + 1;
siz[p] = 1;
for(auto i = head[p]; i; i = i->nxt){
if(SON == ffa)continue;
dfs_pre(SON, p);
siz[p] += siz[SON];
if(siz[SON] > siz[hson[p]])hson[p] = SON;
}
}
void dfs_make(int p = 1, int tp = 1){
top[p] = tp;
static int cdfn(0);
dfn[p] = ++cdfn;
idx[cdfn] = p;
if(hson[p])dfs_make(hson[p], tp);
for(auto i = head[p]; i; i = i->nxt){
if(SON == fa[p] || SON == hson[p])continue;
dfs_make(SON, SON);
}
}
void ModifyTree(int p){
while(top[p] != 1)
st.Modify(dfn[top[p]], dfn[p]), p = fa[top[p]];
st.Modify(1, dfn[p]);
}
ll QueryTree(int p){
ll ret(0);
while(top[p] != 1)
(ret += st.Query(dfn[top[p]], dfn[p])) %= MOD, p = fa[top[p]];
(ret += st.Query(1, dfn[p])) %= MOD;
return ret;
}
int main(){
N = read(), M = read();
for(int i = 2; i <= N; ++i){
int s = i, t = read() + 1;
head[s] = new Edge{head[s], t};
head[t] = new Edge{head[t], s};
}dfs_pre(), dfs_make();
for(int i = 1; i <= M; ++i){
int l = read() + 1, r = read() + 1, p = read() + 1;
qs += {Query{l - 1, p, i, false}, Query{r, p, i, true}};
}sort(qs.begin(), qs.end(), [](const Query &a, const Query &b)->bool{return a.endp < b.endp;});
int cur(0);
for(auto q : qs){
for(int i = cur + 1; i <= q.endp; ++i)ModifyTree(i);
cur = q.endp;
ans[q.idx] += (q.flag ? 1 : -1) * QueryTree(q.val);
}
for(int i = 1; i <= M; ++i)printf("%lld\n", (ans[i] % MOD + MOD) % MOD);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
T3
跳!
UPD
update-2023_01_12 初稿
本文作者:tsawke
本文链接:https://www.cnblogs.com/tsawke/p/17124329.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步