NOIP 模拟赛 7
NOIP 模拟赛总结
NOIP 模拟赛 7
dp != 反悔贪心!
T1 Imbalance
淀粉质 + 二维数点 + 容斥
密码是:MyShiroko。(不带句号 and 括号)
点击查看代码
#include <stdio.h>
#include <string.h>
#include <bitset>
#include <algorithm>
#define lowbit(x) (x & (-x))
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define add(u,v) to[++ tot] = v,nxt[tot] = h[u],h[u] = tot
#define int long long
#define Blue_Archive return 0
using namespace std;
constexpr int N = 5e5 + 3;
constexpr int M = 1e6 + 3;
constexpr int INF = 2e9;
int T;
int n;
int rt;
int tot;
int ans;
int sum;
int top1;
int top2;
int h[N];
int to[M];
int mx[N];
int tr[N];
int siz[N];
int nxt[M];
bitset<N> vis;
struct miku
{
int mx,mn;
friend bool operator < (miku a,miku b){return a.mx == b.mx ? a.mn > b.mn : a.mx < b.mx;}
}lmx[N],lmn[N];
inline int read()
{
int x = 0;
int c = getchar_unlocked();
while(c < '0' || c > '9') c = getchar_unlocked();
while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48),c = getchar_unlocked();
return x;
}
inline void write(int x)
{
if(x < 0) x = -x,putchar_unlocked('-');
if(x > 9) write(x / 10);
putchar_unlocked(x % 10 + '0');
}
inline int max(int x,int y){return x > y ? x : y;}
inline int min(int x,int y){return x < y ? x : y;}
inline void ins(int pos,int val){for(int i = pos;i <= n;i += lowbit(i)) tr[i] += val;}
inline int query(int pos){int res = 0;for(int i = pos;i;i -= lowbit(i)) res += tr[i];return res;}
inline void get(int x,int f)
{
siz[x] = 1;
mx[x] = 0;
for(int i = h[x];i;i = nxt[i])
{
if(to[i] == f || vis[to[i]]) continue;
get(to[i],x);
siz[x] += siz[to[i]];
mx[x] = max(mx[x],siz[to[i]]);
}
mx[x] = max(mx[x],sum - siz[x]);
if(mx[x] < mx[rt]) rt = x;
}
inline void dfs1(int x,int f,int rt,int mxx,int mnn)
{
if(x > mxx)
{
lmx[++ top1] = miku{mxx = x,mnn};
ans += (mnn == rt);
}
if(x < mnn)
{
lmn[++ top2] = miku{mxx,mnn = x};
ans += (mxx == rt);
}
for(int i = h[x];i;i = nxt[i]) if(!vis[to[i]] && to[i] != f) dfs1(to[i],x,rt,mxx,mnn);
}
inline void dfs2(int x,int f,int rt,int mxx,int mnn)
{
if(x > mxx) lmx[++ top1] = miku{mxx = x,mnn};
if(x < mnn) lmn[++ top2] = miku{mxx,mnn = x};
for(int i = h[x];i;i = nxt[i]) if(!vis[to[i]] && to[i] != f) dfs2(to[i],x,rt,mxx,mnn);
}
inline void dfz(int x) // 淀粉质
{
vis[x] = 1;
top1 = top2 = 0;
for(int i = h[x];i;i = nxt[i]) if(!vis[to[i]]) dfs1(to[i],x,x,x,x);
sort(lmx + 1,lmx + top1 + 1);
sort(lmn + 1,lmn + top2 + 1);
int itl = 1,itr = 1;
while(itl <= top1 && itr <= top2) // 端点在其子树的两条链上的合法四元组个数(直接上二维偏序)
{
if(lmn[itr].mx < lmx[itl].mx) ins(lmn[itr ++].mn,1);
else ans += query(lmx[itl ++].mn - 1);
}
while(itl <= top1)
{
if(lmx[itl].mn > 1) ans += query(lmx[itl].mn - 1);
itl ++;
}
while(-- itr) ins(lmn[itr].mn,-1);
for(int i = h[x];i;i = nxt[i]) // 容斥子树的贡献
{
if(vis[to[i]]) continue;
top1 = top2 = 0;
dfs2(to[i],x,x,x,x);
sort(lmx + 1,lmx + top1 + 1);
sort(lmn + 1,lmn + top2 + 1);
int itl = 1,itr = 1;
while(itl <= top1 && itr <= top2) // 端点在其子树的两条链上的合法四元组个数(直接上二维偏序)
{
if(lmn[itr].mx < lmx[itl].mx) ins(lmn[itr ++].mn,1);
else ans -= query(lmx[itl ++].mn - 1);
}
while(itl <= top1)
{
if(lmx[itl].mn > 1) ans -= query(lmx[itl].mn - 1);
itl ++;
}
while(-- itr) ins(lmn[itr].mn,-1);
}
for(int i = h[x];i;i = nxt[i])
{
if(vis[to[i]]) continue;
sum = siz[to[i]];
mx[rt = 0] = INF;
get(to[i],x);
get(rt,0);
dfz(rt);
}
vis[x] = 0;
}
inline void solve()
{
n = read();
for(int i = 1,u,v;i < n;i ++)
{
u = read();
v = read();
add(u,v);
add(v,u);
}
mx[rt = 0] = INF;
sum = n;
get(1,0);
get(rt,0);
dfz(rt);
write(ans);ent;
}
signed main()
{
freopen("imbalance.in","r",stdin);freopen("imbalance.out","w",stdout);
// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
solve();
Blue_Archive;
}
T2 原子
为啥放 T2 ?
简单贪心。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define Blue_Archive return 0
using namespace std;
constexpr int N = 5e5 + 3;
constexpr int M = 1e6 + 3;
int n;
int ans;
int top;
int stk[N];
inline int read()
{
int k = 0,f = 1;
char c = getchar_unlocked();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar_unlocked();
}
while(c >= '0' && c <= '9') k = (k << 3) + (k << 1) + c - '0',c = getchar_unlocked();
return k * f;
}
inline void write(int x)
{
if(x < 0) putchar_unlocked('-'),x = -x;
if(x > 9) write(x / 10);
putchar_unlocked(x % 10 + '0');
}
signed main()
{
freopen("atom.in","r",stdin);freopen("atom.out","w",stdout);
// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
n = read();
for(int i = 1;i < n;i ++) ans += min(i,n - i);
write(ans);ent;
for(int i = 1,k;i < n;i ++)
{
for(int j = 0,sum;j < min(i,n - i);j ++)
{
top = 0;
if(j != 0) stk[++ top] = j,sum += j;
sum = n - 1 - j;
while(sum >= i)
{
sum -= i;
stk[++ top] = i;
}
if(sum) stk[++ top] = sum;
write(top);con;
for(int op = 1;op <= top;op ++) write(stk[op]),con;ent;
}
}
Blue_Archive;
}
// 3995002
T3:旅行计划
赛时想写反悔贪心,狂调不止也没调出来qwq
树形DP,考虑三种情况:
-
到这个点停止的最大贡献。
-
到这个点出去一条边的最大贡献。
-
到这个点出去两条边的最大贡献。
直接 DP 即可。
点击查看代码
#include <stdio.h>
#include <string.h>
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define add(u,v,c) to[++ tot] = v,w[tot] = c,nxt[tot] = h[u],h[u] = tot
#define int long long
#define Blue_Archive return 0
using namespace std;
constexpr int N = 1e6 + 3;
constexpr int M = 2e6 + 3;
int T;
int n;
int tot;
int ans;
int h[N];
int w[M];
int to[M];
int nxt[M];
int dp[N][3];
inline int read()
{
int x = 0;
int c = getchar_unlocked();
while(c < '0' || c > '9') c = getchar_unlocked();
while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48),c = getchar_unlocked();
return x;
}
inline void write(int x)
{
if(x > 9) write(x / 10);
putchar_unlocked(x % 10 + '0');
}
inline int max(int x,int y){return x > y ? x : y;}
inline int min(int x,int y){return x < y ? x : y;}
inline void dfs(int x,int f)
{
dp[x][0] = dp[x][1] = dp[x][2] = 0;
int mx1 = 0,mx2 = 0;
for(int i = h[x];i;i = nxt[i])
{
if(to[i] == f) continue;
dfs(to[i],x);
if(w[i] > 1)
{
dp[x][0] += dp[to[i]][0] + ((w[i] & 1) ? w[i] - 1 : w[i]);
int x = dp[to[i]][1] - dp[to[i]][0] + (w[i] & 1 ? 1 : -1);
if(x > mx1) mx2 = mx1,mx1 = x;
else if(x > mx2) mx2 = x;
}
else
{
if(dp[to[i]][1] + 1 > mx1) mx2 = mx1,mx1 = dp[to[i]][1] + 1;
else if(dp[to[i]][1] + 1 > mx2) mx2 = dp[to[i]][1] + 1;
}
}
dp[x][1] = dp[x][0] + mx1; // 走出去一条边
dp[x][2] = dp[x][0] + mx1 + mx2; // 走出去两条边
for(int i = h[x];i;i = nxt[i])
{
if(to[i] == f) continue;
if(w[i] > 1) dp[x][2] = max(dp[x][2],dp[to[i]][2] - dp[to[i]][0] + dp[x][0]);
}
ans = max(ans,dp[x][2]);
}
inline void solve()
{
tot = ans = 0;
memset(h,0,sizeof(h));
n = read();
for(int i = 1,u,v,c;i < n;i ++)
{
u = read();
v = read();
c = read();
add(u,v,c);
add(v,u,c);
}
dfs(1,0);
write(ans);ent;
}
signed main()
{
freopen("plan.in","r",stdin);freopen("plan.out","w",stdout);
// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
T = read();
while(T --) solve();
Blue_Archive;
}
T4:逃离冰场(skate)
不会,咕咕。
与你的日常,便是奇迹

浙公网安备 33010602011771号