2022.10.21 模拟赛小结
目录sssmzy AK 了,zpair 差一点 AK 了,我寄了。
一套难得的难度略低于 NOIP 的阳间模拟赛
虽然还是寄了
更好的阅读体验戳此进入
赛时思路
T1
有 $ f(x) = \lfloor \sqrt[4]{x} + \dfrac{1}{2} \rfloor \(,\) T $ 组询问,给定 $ n $,求 $ \sum_{i = 1}^n = \dfrac{1}{f(i)} $。强制在线。
难得切掉的一道水题。
第一眼值域分块,然后发现不是,于是考虑对于 $ f(x) $ 显然取值是一段一段的,且段长递增,于是我们维护一下每一段的初始值,然后做个前缀和,考虑好加 $ 1 $ 减 $ 1 $ 的边界,每次询问 lower_bound
$ O(\log n) $ 查询一下即可。题解里也有 $ O(1) $ 查询的方法,大概就是嗯推一下柿子。
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(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
// using namespace __gnu_pbds;
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);
char buf_ans[114];
ll next_n(double last_ans=0,ll get_n=0){//last_ans<n<=1e18
sprintf(buf_ans,"%.6f",last_ans);
for(ll i=0,x=0;;i++){if(buf_ans[i]=='.')return get_n^x;if(i&1)x*=10;
else x=x*10+(buf_ans[i]^48);}}
const int mx = 34900;
ll blk[40000];
ll sum[40000];
double lans(0.0);
int main(){
freopen("function.in", "r", stdin);
freopen("function.out", "w", stdout);
int T = read();
blk[1] = 1; sum[1] = 5.0;
for(int i = 1; i <= 35000; ++i)
blk[i + 1] = (ll)ceil(powl((ld)i + 0.5, 4));
for(int i = 1; i <= 34990; ++i)
sum[i + 1] = sum[i] + (ld)1.0 / (ld)(i + 1) * (ld)(blk[i + 2] - blk[i + 1]);
// for(int i = 1; i <= 100; ++i){
// printf("%lld : %lld\n", blk[i], sum[i]);
// }
while(T--){
ll n = read<ll>();
n = next_n(lans, n);
// printf("%lld\n", n);
int dist = lower_bound(blk + 1, blk + mx + 1, n) - blk;
// printf("dis:%d\n", dist);
// dist -= blk[dist] == n ? 1 : 2;
--dist;
// printf("new dis:%d\n", dist);
// if(n == 89)printf("val: %lld + %.6Lf / %.6Lf\n", sum[dist - 1], (ld)(n - blk[dist] + 1), (ld)dist);
ld ans = n == blk[dist + 1]
? (sum[dist] + (ld)(n - blk[dist + 1] + 1) / (ld)(dist + 1))
: (sum[dist - 1] + (ld)(n - blk[dist] + 1) / (ld)dist);
printf("%.6Lf\n", ans);
lans = (double)ans;
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short 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
给定 $ n $ 个点以 $ 1 $ 为根的树,初始所有节点权值为 $ 0 \(,\) q $ 个操作或询问,操作为给定 $ v, x, k $,对 $ v $ 及其子树,记节点与 $ v $ 的距离为 $ dis $,则对每个节点的权值加上 $ x - dis \times k $,询问为给定 $ v $ 输出 $ v $ 的权值。
又把 10.19 口糊的那个通过 bfs 序转称序列上然后套线段树的塞上去了,大概可以认为是暴力 + 大剪枝,树越扁剪枝越大,树是链的话就退化成暴力。
本来应该能拿到一些分的,然后线段树的 query
忘了取模了,直接全寄爆零。
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(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
// using namespace __gnu_pbds;
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 (1000000007)
template<typename T = int>
inline T read(void);
struct Edge{
Edge* nxt;
int to;
OPNEW;
}ed[610000];
ROPNEW(ed);
Edge* head[310000];
int N, Q;
int idx[310000], ridx[310000];
int dsl[310000], dsr[310000];
void bfs(void){
int cnt(0);
queue < pair < int, int >/*vertex, father*/ > q;
q.push({1, 0});
while(!q.empty()){
auto p = q.front(); q.pop();
idx[p.first] = ++cnt;
ridx[cnt] = p.first;
vector < pair < int, int > > tmp;
for(auto i = head[p.first]; i; i = i->nxt)
if(SON != p.second)
q.push({SON, p.first});
if(!dsl[idx[p.second]])dsl[idx[p.second]] = dsr[idx[p.second]] = idx[p.first];
else dsr[idx[p.second]] = idx[p.first];
}
}
class SegTree{
private:
ll st[310000 << 2];
ll lz[310000 << 2];
#define LS (p << 1)
#define RS ((p << 1) + 1)
#define MID ((gl + gr) >> 1)
public:
// void Pushup(int p){st[p] = st[LS] + st[RS];}
void Pushdown(int p){
st[LS] = (st[LS] + lz[p]) % MOD, st[RS] = (st[RS] + lz[p]) % MOD;
lz[LS] = (lz[LS] + lz[p]) % MOD, lz[RS] = (lz[RS] + lz[p]) % MOD;
lz[p] = 0;
}
void Modify(int l, int r, ll val, int p = 1, int gl = 1, int gr = N){
if(l <= gl && gr <= r)return st[p] = (st[p] + val) % MOD, lz[p] = (lz[p] + val) % MOD, void();
Pushdown(p);
if(l <= MID)Modify(l, r, val, LS, gl, MID);
if(MID + 1 <= r)Modify(l, r, val, RS, MID + 1, gr);
}
ll Query(int idx, int p = 1, int gl = 1, int gr = N){
if(gl == gr)return st[p];
Pushdown(p);
if(idx <= MID)return Query(idx, LS, gl, MID);
else return Query(idx, RS, MID + 1, gr);
}
}st;
void Mdf(int p, ll val, int k){
int l(p), r(p), dis(0);
st.Modify(l, r, (val - (ll)dis * k + MOD) % MOD);
while(true){
++dis;
while(!dsl[l] && l <= r)++l;
while(!dsr[r] && l <= r)--r;
if(l > r)return;
l = dsl[l], r = dsr[r];
st.Modify(l, r, (val - (ll)dis * k + MOD) % MOD);
}
}
int main(){
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
N = read();
for(int i = 2; i <= N; ++i){
int fa = read();
head[i] = new Edge{head[i], fa};
head[fa] = new Edge{head[fa], i};
}bfs();
Q = read();
while(Q--){
int opt = read();
if(opt == 1){
int v = read(), x = read(), k = read();
Mdf(idx[v], (ll)x, k);
}else{
int v = read();
printf("%lld\n", (st.Query(idx[v]) + MOD) % MOD);
}
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short 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
给定序列 $ a_n $,保证 $ 1 \le a_i \le 8 $,求一个最长子序列满足:1. $ \left[ 1, 8 \right] $ 任意两个整数出现次数之差不大于 $ 1 $。2. 每种数字必须连续出现。
没想出来,暴力 $ 10\texttt{pts} $ 跑路。
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(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
// using namespace __gnu_pbds;
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 arr[1100];
vector < int > cur;
int ans(0);
bool Check(void){
int len[10];
memset(len, 0, sizeof len);
int lst(-1);
for(auto i : cur){
if(i == lst)++len[i];
else if(len[i]++)return false;
}
int mn(INT_MAX), mx(INT_MIN);
for(int i = 1; i <= 8; ++i)mn = min(mn, len[i]), mx = max(mx, len[i]);
return mx - mn <= 1;
}
void dfs(int dep){
if(dep > N){
if(Check())ans = max(ans, (int)cur.size());
return;
}
cur.emplace_back(arr[dep]);
dfs(dep + 1);
cur.pop_back();
dfs(dep + 1);
}
int main(){
freopen("card.in", "r", stdin);
freopen("card.out", "w", stdout);
N = read();
for(int i = 1; i <= N; ++i)arr[i] = read();
if(N <= 25)dfs(1), printf("%d\n", ans), exit(0);
// while((double)clock() / CLOCKS_PER_SEC <= 0.95){
// int siz = rndd(1, N);
// for(int i = 1; i <= N; ++i){
// }
printf("%d\n", rndd(1, N));
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short 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;
}
T4
原题 CF1051F The Shortest Statement。
寄了,写的暴力也挂了。
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(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
// using namespace __gnu_pbds;
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, M;
int Q;
int lca[110000];
int dep[110000];
pair < int, int > ask[110000];
ll ans[110000];
pair < int, int /*vertex, val*/ > ffa[110000];
struct Edge{
Edge* nxt;
int to;
int val;
OPNEW;
}ed[310000];
ROPNEW(ed);
Edge* head[110000];
namespace Tree{
vector < pair < int, int > /*vertex, query_idx*/ > query[110000];
bool vis[110000];
class UnionFind{
private:
int fa[110000];
public:
UnionFind(void){for(int i = 1; i <= N; ++i)fa[i] = i;}
int Find(int x){return x == fa[x] ? x : (fa[x] = Find(fa[x]));}
void Union(int s, int t){fa[t] = Find(s);}
}uf;
void Init(void){
for(int i = 1; i <= Q; ++i){
int u = read(), v = read();
ask[i] = {u, v};
query[u].emplace_back(v, i);
query[v].emplace_back(u, i);
}
}
void dfs(int p = 1, int fa = 0){
vis[p] = true;
for(auto i = head[p]; i; i = i->nxt)if(SON != fa && !vis[SON])dfs(SON, p), uf.Union(p, SON);
for(auto q : query[p])if(vis[q.first])lca[q.second] = uf.Find(q.first);
}
void dfs_dep(int p = 1, int fa = 0){
dep[p] = dep[fa] + 1;
for(auto i = head[p]; i; i = i->nxt)if(SON != fa)ffa[SON] = {p, i->val}, dfs_dep(SON, p);
}
}
int main(){
freopen("statement.in", "r", stdin);
freopen("statement.out", "w", stdout);
N = read(), M = read();
for(int i = 1; i <= M; ++i){
int s = read(), t = read(), v = read();
head[s] = new Edge{head[s], t, v};
head[t] = new Edge{head[t], s, v};
}Q = read();
if(M == N - 1){
Tree::Init();
Tree::dfs();
Tree::dfs_dep();
for(int i = 1; i <= Q; ++i){
ll anss(0);
int cp(ask[i].first);
while(cp != lca[i]){
anss += ffa[cp].second;
cp = ffa[cp].first;
}
cp = ask[i].second;
while(cp != lca[i]){
anss += ffa[cp].second;
cp = ffa[cp].first;
}
printf("%lld\n", anss);
}
exit(0);
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short 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
考虑对于每次修改 $ v, x, k \(,\) v $ 子树(包括 $ v $)下的 $ u $,修改量为 $ x - dis(u, v) \times k $,因为是在树上,所以可以转化成 $ x - (dep_v - dep_u) \times k \(,展开一下:\) x + dep_u \times k - dep_v \times k $,然后发现式子里对于点 $ v \(,\) dep_v $ 是定值,所以开个线段树(或树状数组)维护一下 $ x + dep_u \times k $ 和 $ k $ 即可。然后这样的话每次修改就等于是对一整个子树的修改,考虑如何转到序列上,显然按照 dfs 序即可。
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(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
// using namespace __gnu_pbds;
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 (1000000007)
template<typename T = int>
inline T read(void);
struct Edge{
Edge* nxt;
int to;
OPNEW;
}ed[610000];
ROPNEW(ed);
Edge* head[310000];
int N, Q;
int idx[310000];
int dep[310000], siz[310000];
void dfs(int p = 1, int fa = 0){
static int cnt(0);
idx[p] = ++cnt;
dep[idx[p]] = dep[idx[fa]] + 1;
++siz[idx[p]];
for(auto i = head[p]; i; i = i->nxt)if(SON != fa)dfs(SON, p), siz[idx[p]] += siz[idx[SON]];
}
class BIT{
private:
pair < ll, ll > tr[310000];
public:
int lowbit(int x){return x & -x;}
void add(int x, int u, ll base, ll k){
while(x <= N)
tr[x] = {
((tr[x].first + base + MOD) % MOD + (dep[u] * k + MOD) % MOD + MOD) % MOD,
(tr[x].second + k + MOD) % MOD
},
x += lowbit(x);
}
void modify(int l, int r, int u, ll base, ll k){
// printf("Modifying [%d, %d] => u = %d, x = %lld, k = %lld\n", l, r, u, base, k);
add(l, u, base, k);
add(r + 1, u, -base, -k);
}
ll query(int x){
int rx = x;
ll ret(0);
while(x)ret = ((ret + tr[x].first) % MOD - tr[x].second * dep[rx] % MOD + MOD) % MOD, x -= lowbit(x);
return ret;
}
}bit;
int main(){
N = read();
for(int i = 2; i <= N; ++i){
int fa = read();
head[i] = new Edge{head[i], fa};
head[fa] = new Edge{head[fa], i};
}dfs();
Q = read();
while(Q--){
// for(int i = 1; i <= N; ++i)printf("%lld%c", ta.query(i), i == N ? '\n' : ' ');
int opt = read();
if(opt == 1){
int v = read(), x = read(), k = read();
bit.modify(idx[v], idx[v] + siz[idx[v]] - 1, idx[v], x, k);
}else{
int v = read();
printf("%lld\n", bit.query(idx[v]) % MOD);
}
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short 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 T4
咕咕咕。
UPD
update-2022_10_21 初稿
标签:return,21,int,2022.10,void,ret,getchar,小结,define From: https://www.cnblogs.com/tsawke/p/16820298.html