2022NOIP A层联测27
A. 天平
发现是求最少用多少数,使得他们的 \(gcd\) 为整个序列所有数的 \(gcd\)
因为一个数不停取 \(gcd\) 最多就 \(log\), 直接开 \(map\) 转移即可
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 55;
int a[maxn], g, n;
map<int, int> mp;
int main(){
freopen("weights.in","r",stdin);
freopen("weights.out","w",stdout);
n = read();
for(int i = 1; i <= n; ++i)a[i] = read();
g = a[1];
for(int i = 2; i <= n; ++i)g = __gcd(g, a[i]);
for(int i = 1; i <= n; ++i){
mp[a[i]] = 1;
for(auto x : mp){
int to = __gcd(x.first, a[i]);
if(mp[to] == 0 || mp[to] > x.second + 1)mp[to] = x.second + 1;
}
}
printf("%d\n",mp[g]);
return 0;
}
B. 支配数据
树套树
每 \(n\) 个数用一颗线段树维护,动态开点,没有点的看成初始值,比较方便的办法是用类似主席树的思想
外层一棵线段树维护区间覆盖的标记,和整区间最小值
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 100005;
int b[maxn], n, k, root[maxn];
struct seg{
struct node{
int l, r, val;
bool tag;
}t[maxn * 160];
int cnt, c0;
void push_up(int x){t[x].val = min(t[t[x].l].val, t[t[x].r].val);}
void upd(int x, int val){t[x].val = val; t[x].tag = true;}
void push_down(int x){
if(t[x].l <= c0)t[x].l = ++cnt;
if(t[x].r <= c0)t[x].r = ++cnt;
upd(t[x].l, t[x].val);
upd(t[x].r, t[x].val);
t[x].tag = false;
}
int built(int l, int r){
int now = ++cnt;
if(l == r){t[now].val = b[l];return now;}
int mid = (l + r) >> 1;
t[now].l = built(l, mid);
t[now].r = built(mid + 1, r);
push_up(now); return now;
}
int modify(int x, int l, int r, int L, int R, int val){
int now = x; if(now <= c0)now = ++cnt, t[now] = t[x], t[now].tag = 0;
if(L <= l && r <= R){upd(now, val);return now;}
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1;
if(L <= mid)t[now].l = modify(t[x].l, l, mid, L, R, val);
if(R > mid)t[now].r = modify(t[x].r, mid + 1, r, L, R, val);
push_up(now); return now;
}
int query(int x, int l, int r, int L, int R){
if(L <= l && r <= R)return t[x].val;
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1, ans = INT_MAX;
if(L <= mid)ans = min(ans, query(t[x].l, l, mid, L, R));
if(R > mid)ans = min(ans, query(t[x].r, mid + 1, r, L, R));
return ans;
}
}t;
struct segmi{
struct node{
int val, tag;
}t[maxn << 2 | 1];
void upd(int x, int val){t[x].val = t[x].tag = val;}
void push_up(int x){t[x].val = min(t[x << 1].val, t[x << 1 | 1].val);}
void push_down(int x){upd(x << 1, t[x].val); upd(x << 1 | 1, t[x].val); t[x].tag = 0;}
void built(int x, int l, int r, int val){
t[x].val = val; t[x].tag = 0;
if(l == r)return;
int mid = (l + r) >> 1;
built(x << 1, l, mid, val);
built(x << 1 | 1, mid + 1, r, val);
}
void modify(int x, int l, int r, int L, int R, int val){
if(L <= l && r <= R){upd(x, val); return;}
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1;
if(L <= mid)modify(x << 1, l, mid, L, R, val);
if(R > mid)modify(x << 1 | 1, mid + 1, r, L, R, val);
push_up(x);
}
void modify_one(int x, int l, int r, int pos, int val){
if(l == r){
t[x].val = val;
t[x].tag = 0;
return;
}
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1;
if(pos <= mid)modify_one(x << 1, l, mid, pos, val);
else modify_one(x << 1 | 1, mid + 1, r, pos, val);
push_up(x);
}
int query(int x, int l, int r, int L, int R){
if(L <= l && r <= R)return t[x].val;
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1, ans = INT_MAX;
if(L <= mid)ans = min(ans, query(x << 1, l, mid, L, R));
if(R > mid)ans = min(ans, query(x << 1 | 1, mid + 1, r, L, R));
return ans;
}
int query(int x, int l, int r, int pos){
if(l == r)return t[x].tag;
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1;
if(pos <= mid)return query(x << 1, l, mid, pos);
else return query(x << 1 | 1, mid + 1, r, pos);
}
}T;
void modify(int l, int r){
int x = read();
int L = (l + n - 1) / n;
int R = (r + n - 1) / n;
if(L + 1 <= R - 1)T.modify(1, 1, k, L + 1, R - 1, x);
int ql = T.query(1, 1, k, L); int qr = T.query(1, 1, k, R);
if(ql)root[L] = t.modify(root[L], 1, n, 1, n, ql);
if(qr)root[R] = t.modify(root[R], 1, n, 1, n, qr);
l = (l - 1) % n + 1; r = (r - 1) % n + 1;
if(L != R){
root[L] = t.modify(root[L], 1, n, l, n, x);
root[R] = t.modify(root[R], 1, n, 1, r, x);
ql = t.query(root[L], 1, n, 1, n);
qr = t.query(root[R], 1, n, 1, n);
T.modify_one(1, 1, k, L, ql);
T.modify_one(1, 1, k, R, qr);
}else{
root[L] = t.modify(root[L], 1, n, l, r, x);
ql = t.query(root[L], 1, n, 1, n);
T.modify_one(1, 1, k, L, ql);
}
}
int query(int l, int r){
int L = (l + n - 1) / n;
int R = (r + n - 1) / n;
int ans = INT_MAX;
if(L + 1 <= R - 1)ans = T.query(1, 1, k, L + 1, R - 1);
int ql = T.query(1, 1, k, L);
int qr = T.query(1, 1, k, R);
if(ql)root[L] = t.modify(root[L], 1, n, 1, n, ql);
if(qr)root[R] = t.modify(root[R], 1, n, 1, n, qr);
l = (l - 1) % n + 1; r = (r - 1) % n + 1;
if(L != R){
ans = min(ans, t.query(root[L], 1, n, l, n));
ans = min(ans, t.query(root[R], 1, n, 1, r));
}else ans = min(ans, t.query(root[L], 1, n, l, r));
return ans;
}
int main(){
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
n = read(), k = read();
for(int i = 1; i <= n; ++i)b[i] = read();
root[1] = t.built(1, n); for(int i = 2; i <= k; ++i)root[i] = root[1];
T.built(1, 1, k, t.query(root[1], 1, n, 1, n)); t.c0 = t.cnt;
int q = read();
for(int i = 1; i <= q; ++i){
int op = read(), l = read(), r = read();
if(op & 1) modify(l, r);
else printf("%d\n",query(l, r));
}
return 0;
}
C. 信息学的尽头
基环树 \(DP\)
肯定先把环找出来
拆掉环边考虑当前子树
子树内贡献简单的换根 \(DP\)
如何处理子树外的
考虑他们肯定要先到当前根节点,于是处理这个,然后就是简单的统计答案了
考虑在环上,依次考虑每个点,其他点到他肯定一侧顺时针一侧逆时针,那么就存在一个分界点,而随着当前点的顺序移动,分界点一定只会同向移动,于是使用双指针即可
考场调不出来,于是在环上爆扫,因为数据水过了
现在是正确的
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 200005;
const ll inf = 0x3f3f3f3f3f3f3f3f;
typedef pair<int, int> pii;
struct DSU{
int f[maxn];
void init(int x){for(int i = 1; i <= x; ++i)f[i] = i;}
int fa(int x){return x == f[x] ? x : f[x] = fa(f[x]);}
bool merge(int u, int v){u = fa(u); v = fa(v); if(u == v)return false; f[u] = v; return true;}
}UN;
int head[maxn], tot;
struct edge{int to, net, val;}e[maxn << 1 | 1];
void add(int u, int v, int w){
e[++tot].net = head[u];
head[u] = tot;
e[tot].to = v;
e[tot].val = w;
}
int n;
bool in[maxn];
int fa[maxn];
ll rval[maxn], ans[maxn];
vector<pii>vec;
void prefind(int x){
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to; if(v == fa[x])continue;
fa[v] = x; rval[v] = e[i].val; prefind(v);
}
}
void tag(int u){while(fa[u]){in[u] = true; vec.push_back(pii(u, rval[u])); u = fa[u];}in[u] = true;}
int siz[maxn];
void dfs(int x){
siz[x] = 1; rval[x] = 0;
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(in[v] || v == fa[x])continue;
fa[v] = x;
dfs(v);
siz[x] += siz[v];
rval[x] += rval[v];
rval[x] += 1ll * siz[v] * e[i].val;
}
}
int S;
void sol(int x){
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(in[v] || v == fa[x])continue;
rval[v] = rval[x] + 1ll * (S - siz[v] - siz[v]) * e[i].val;
sol(v);
}
}
void modify(int x, ll val, int S, ll dis){
ans[x] += val + S * dis;
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(in[v] || v == fa[x])continue;
modify(v, val, S, dis + e[i].val);
}
}
ll dis[maxn + maxn], sdis[maxn + maxn];
int si[maxn + maxn], ss[maxn + maxn], sp[maxn];
ll g[maxn + maxn];
int main(){
freopen("end.in","r",stdin);
freopen("end.out","w",stdout);
n = read(); UN.init(n);
for(int i = 1; i <= n; ++i){
int u = read(), v = read(), w = read();
if(UN.merge(u, v) == false){prefind(u); vec.push_back(pii(u, w)); tag(v);}
add(u, v, w); add(v, u, w);
}
for(int i = 1; i <= n; ++i)fa[i] = 0;
for(pii x : vec){dfs(x.first); S = siz[x.first]; sol(x.first);}
for(int i = 1; i <= n; ++i)ans[i] = rval[i];
ll sval = 0; int cnt = 0;
for(pii x : vec){
sval += rval[x.first];
si[++cnt] = siz[x.first];
dis[cnt] = x.second;
}
for(int i = 1; i <= cnt; ++i)si[i + cnt] = si[i], dis[i + cnt] = dis[i];
for(int i = 1; i <= cnt + cnt; ++i)sdis[i] = sdis[i - 1] + dis[i], ss[i] = ss[i - 1] + si[i];
for(int i = 1; i <= cnt + cnt; ++i)g[i] = g[i - 1] + si[i] * sdis[i - 1];
int p = 1;
for(int i = 1; i <= cnt; ++i){
while(p < i + cnt && sdis[p] - sdis[i - 1] < sdis[i + cnt - 1] - sdis[p])++p;
sp[i] = p;
}
for(int i = 1; i <= cnt; ++i){
int now = vec[i - 1].first;
ll dt = sval - rval[now];
if(sp[i] > i)dt += g[sp[i]] - g[i] - sdis[i - 1] * (ss[sp[i]] - ss[i]);
if(sp[i] < i + cnt - 1) dt += - g[i + cnt - 1] + g[sp[i]] + sdis[i + cnt - 1] * (ss[i + cnt - 1] - ss[sp[i]]);
modify(now, dt, n - si[i], 0);
}
for(int i = 1; i <= n; ++i)printf("%lld ", ans[i]);
printf("\n");
return 0;
}
D. 球对称薛定谔方程
神奇 \(DP\)
\(AGC024E\) 题解看洛谷吧。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 305;
int n, k, mod;
int f[maxn][maxn][maxn];
void add(int &x, int y){x += y; x = x >= mod ? x - mod : x;}
int main(){
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
cin >> n >> k >> mod;
f[0][1][0] = 1;
for(int i = 0; i <= n; ++i){
for(int j = 1; j <= k; ++j){
for(int p = i; p >= 1; --p)add(f[i][j][p - 1], f[i][j][p]);
add(f[i][j + 1][i], f[i][j][0]);
for(int p = 0; p <= i; ++p)add(f[i + 1][j][p], 1ll * (p + 1) * f[i][j][p] % mod);
}
}
cout << f[n][k][0] << endl;
return 0;
}