NOIP2022模拟赛by Yjc1

T1

CF1311F

分类讨论二位偏序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define maxn 200005
#define put() putchar('\n')
using namespace std;
inline void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
int n,g[maxn],tot,ans;
struct yyy{
int x,v;
}a[maxn];
inline bool cmp(yyy x,yyy y) {return x.x==y.x?x.v<=y.v:x.x<y.x;}
struct BIT{
#define lowbit(x) ((x)&(-x))
int f[maxn];
inline void add(int x,int y) {for (;x<=n;x+=lowbit(x)) f[x]+=y;}
inline int query(int x) {int sum=0;for (;x;x-=lowbit(x)) sum+=f[x];return sum;}
}t1,t2;
signed main(void){
//freopen("1.in","r",stdin);
int i;
read(n);
for (i=1;i<=n;i++) read(a[i].x);
for (i=1;i<=n;i++) read(a[i].v),g[++tot]=a[i].v;
sort(g+1,g+1+tot);
tot=unique(g+1,g+1+tot)-g-1;
for (i=1;i<=n;i++) a[i].v=lower_bound(g+1,g+1+tot,a[i].v)-g;
sort(a+1,a+1+n,cmp);
// for (i=1;i<=n;i++) printf("%lld %lld\n",a[i].x,a[i].v);
for (i=1;i<=n;i++) {
ans+=a[i].x*t1.query(a[i].v)+t2.query(a[i].v);
t1.add(a[i].v,1),t2.add(a[i].v,-a[i].x);
}
printf("%lld",ans);
return 0;
}

T2

bzoj1489

两个条件,两个最长上升子序列,长度都为 $n/2$,对于序列前 $i$ 个的两个子序列,一个以 $a_i$ 结尾,根据贪心另一个越小越好。

令 $f[i][j]$ 表示序列前 $i$ 个组成的两条子序列,一个是以 $a_i$ 结尾的长度为 $j$ 的子序列,另一个以 $f[i][j]$ 结尾。

考虑转移:

  • $a_i$ 加到 $a_{i-1}$ 的后面,满足条件 $a_i>a_{i-1}$ ,$f[i][j]=\min(f[i][j],f[i-1][j-1])$。
  • $a_i$ 加到另一个子序列的后面,满足条件 $a_i>f[i][i-j]$ ,$f[i][j]=\min(f[i][j],a_{i-1})$

判断 $f_{n,n/2}$ 是否有值即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define maxn 2005
#define put() putchar('\n')
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
using namespace std;
inline void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
namespace Debug{
Tp void _debug(char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts void _debug(char* f,Ty x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,vector<Ty>& V){os<<"[";for(auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug(#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
int n,a[maxn],f[maxn][maxn];
inline void solve(void) {
int i,j;
read(n);
for (i=1;i<=n;i++) read(a[i]);
for (i=0;i<=n;i++) for (j=0;j<=n/2;j++) f[i][j]=1e9;
f[0][0]=-1e9;a[0]=-1e9;
for (i=1;i<=n;i++) {
for (j=1;j<=min(n/2,i);j++){
if (a[i]>a[i-1]) f[i][j]=min(f[i][j],f[i-1][j-1]);
if (a[i]>f[i-1][i-j]) f[i][j]=min(f[i][j],a[i-1]);
}
}
if (f[n][n/2]<1e8) puts("Suck!");
else puts("YYyyds!");
}
signed main(void){
int T;
read(T);
while (T--) solve();
return 0;
}

T3

bzoj2221 cf765F

考虑 $i<j,a_i<a_j$ 且有贡献的点。

首先在找到在 $i$ 右边且第一个在区间 $[a_i+1,\infty)$ 的点,记为 $a_x$。

然后在 $x$ 右边第一个在区间 $[a_i+1,(a_x+a_i)/2)$ 的点。显然这与在 $i$ 右边是等价的。所以可以用扫描线解决。

一直找找找,每次值域至少缩小一半,对 $a_i$ 有贡献的个数就是 $\log$ 的。

$i<j,a_i>a_j$ 同理。

查询的时候询问离线,树状数组维护即可。

复杂度 $O(n\log^2n)$,不需要用到随机的性质。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define maxn 100005
#define put() putchar('\n')
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
using namespace std;
inline void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
namespace Debug{
Tp void _debug(char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts void _debug(char* f,Ty x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,vector<Ty>& V){os<<"[";for(auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug(#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
int n,q,a[maxn],root;
const int inf=2e9,base=1e9;
namespace Segment{
struct yyy{
int ls,rs,Min;
yyy(int a=inf) {Min=a;}
}f[maxn*50];
int cnt=0;
inline void clear(void) {
for (int i=1;i<=cnt;i++) f[i].ls=f[i].rs=0,f[i].Min=inf;
cnt=0;root=0;
}
inline void Update(int l,int r,int &rt,int head,int k) {
if (!rt) rt=++cnt;f[rt].Min=min(f[rt].Min,k);
if (l==r) return void();
int mid=l+r>>1;
if (head<=mid) Update(l,mid,f[rt].ls,head,k);
else Update(mid+1,r,f[rt].rs,head,k);
}
inline int Query(int l,int r,int &rt,int head,int tail) {
if (!rt) return inf;
if (head<=l&&r<=tail) return f[rt].Min;
int mid=l+r>>1,tmp1=inf,tmp2=inf;
if (head<=mid) tmp1=Query(l,mid,f[rt].ls,head,tail);
if (tail>mid) tmp2=Query(mid+1,r,f[rt].rs,head,tail);
return min(tmp1,tmp2);
}
};
struct BIT{
#define lowbit(x) ((x)&(-x))
int f[maxn];
inline void clear(void) {memset(f,0x3f,sizeof(f));}
inline void update(int x,int y) {for (;x<=n;x+=lowbit(x)) f[x]=min(f[x],y);}
inline int query(int x) {int ans=inf;for (;x;x-=lowbit(x)) ans=min(ans,f[x]);return ans;}
}t;
vector<int>to[maxn];
vector<pair<int,int> >h[maxn];
int ans[maxn];
signed main(void){
int i,tmp,l,r;
read(n);read(q);
for (i=1;i<=n;i++) read(a[i]);
for (i=n;i>=1;i--) {
int now=inf;
while (a[i]+1<=now) {
tmp=Segment::Query(0,base,root,a[i]+1,now);
if (tmp>=inf) break;
to[tmp].push_back(i);
now=(a[i]+a[tmp])/2-1;
}
Segment::Update(0,base,root,a[i],i);
}
Segment::clear();
for (i=n;i>=1;i--) {
int now=0;
while (now<=a[i]-1) {
tmp=Segment::Query(0,base,root,now,a[i]-1);
if (tmp>=inf) break;
to[tmp].push_back(i);
now=(a[i]+a[tmp])/2+1;
}
Segment::Update(0,base,root,a[i],i);
}
for (i=1;i<=q;i++) {
read(l);read(r);
h[r].push_back(make_pair(l,i));
}
t.clear();
for (i=1;i<=n;i++) {
for (auto y:to[i]) t.update(n-y+1,abs(a[i]-a[y]));
for (auto tmp:h[i]) {
ans[tmp.second]=t.query(n-tmp.first+1);
}
}
for (i=1;i<=q;i++) printf("%lld\n",ans[i]);
return 0;
}

T4

bzoj4400 [TJOI2012]桥

跑个 $1$ 为起点的最短路径树,对于点 $i$ ,在树上到最短路上最近的点 $L_i$。跑个 $n$ 为节点的最短路径树,在树上的最近的点为 $R_i$。

如果这条边 $(x,y,z)$ 有贡献,那么当且仅当删除 $[L_i,R_i]$ 中的一条边,可能更新为 $dis1_x+z+disn_y$。所以用线段树维护一下最小值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define maxn 200005
#define put() putchar('\n')
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
using namespace std;
inline void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
namespace Debug{
Tp void _debug(char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts void _debug(char* f,Ty x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,vector<Ty>& V){os<<"[";for(auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug(#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
int n,m;
const int inf=1e10;
int head=1,h[maxn];
struct node{
int to,z,w,flag;
inline void add(int x,int y,int val) {
to=y;z=h[x];h[x]=head;w=val;
}
}a[maxn*4];
int vis[maxn],diss[maxn],dist[maxn],flag[maxn],pre[maxn];
int stac[maxn],tot,L[maxn],R[maxn],id[maxn];
inline int dfs1(int x) {
if (flag[x]) return L[x]=x;
if (L[x]) return L[x];
return L[x]=dfs1(a[pre[x]^1].to);
}
inline int dfs2(int x) {
if (flag[x]) return R[x]=x;
if (R[x]) return R[x];
return R[x]=dfs2(a[pre[x]^1].to);
}
int f[maxn<<2];
inline void Update(int l,int r,int rt,int head,int tail,int k) {
if (head<=l&&r<=tail) return f[rt]=min(f[rt],k),void();
int mid=l+r>>1;
if (head<=mid) Update(l,mid,rt<<1,head,tail,k);
if (tail>mid) Update(mid+1,r,rt<<1|1,head,tail,k);
}
inline int Query(int l,int r,int rt,int head) {
if (l==r) return f[rt];
int mid=l+r>>1,tmp=inf;
if (head<=mid) tmp=Query(l,mid,rt<<1,head);
else tmp=Query(mid+1,r,rt<<1|1,head);
return min(tmp,f[rt]);
}
int ans=0,anss=0;
priority_queue<pair<int,int> >q;
signed main(void){
// freopen("1.in","r",stdin);
int i,x,y,z,tmp;
read(n);read(m);
for (i=1;i<=m;i++) {
read(x);read(y);read(z);
a[++head].add(x,y,z);
a[++head].add(y,x,z);
}
memset(f,0x3f,sizeof(f));
memset(diss,0x3f,sizeof(diss));
memset(dist,0x3f,sizeof(dist));
diss[1]=0;q.push({0,1});
while (!q.empty()) {
x=q.top().second;q.pop();
if(vis[x])continue;vis[x]=1;
for (i=h[x];i;i=a[i].z)
if (diss[a[i].to]>diss[x]+a[i].w) {
pre[a[i].to]=i;
diss[a[i].to]=diss[x]+a[i].w;
q.push({-diss[a[i].to],a[i].to});
}
}
int now=n;flag[n]=1,stac[tot=1]=n;
while (pre[now]) {
i=pre[now];
flag[a[i^1].to]=1;a[i^1].flag=a[i].flag=1;
stac[++tot]=a[i^1].to,now=a[i^1].to;
}
reverse(stac+1,stac+1+tot);
for (i=1;i<=tot;i++) id[stac[i]]=i;
// for (cerr<<tot<<endl,i=1;i<=tot;i++) gdb(stac[i]);

for (i=1;i<=n;i++) L[i]=dfs1(i);
dist[n]=0;
memset(pre,0,sizeof(pre));
memset(vis,0,sizeof(vis));
while (!q.empty()) q.pop();
q.push({0,n});
while (!q.empty()) {
x=q.top().second;q.pop();
if (vis[x]) continue;
vis[x]=1;
for (i=h[x];i;i=a[i].z)
if ((a[i].flag&&pre[a[i].to]!=i&&dist[a[i].to]>=dist[x]+a[i].w)||dist[a[i].to]>dist[x]+a[i].w) {
pre[a[i].to]=i;
dist[a[i].to]=dist[x]+a[i].w;
// if (a[i].to==2) gdb(x,a[i].flag,a[i].to,dist[a[i].to]);
q.push({-dist[a[i].to],a[i].to});
}
}
for (i=1;i<=n;i++) R[i]=dfs2(i);
for (i=2;i<=head;i++) {
x=a[i^1].to,y=a[i].to,z=a[i].w;
if (a[i].flag) continue;
// gdb(x,y,z,diss[x]+z+dist[y],id[L[x]],id[R[y]]);
if (id[L[x]]<id[R[y]]) Update(1,tot-1,1,id[L[x]],id[R[y]]-1,diss[x]+z+dist[y]);
}

for (i=1;i<tot;i++) {
tmp=Query(1,tot-1,1,i);
// gdb(i,tmp);
if (tmp>1e15) continue;
if (ans<tmp) ans=tmp,anss=1;else if (ans==tmp) anss++;
}
if (ans==diss[n]) printf("%lld %lld\n",diss[n],m);else
printf("%lld %lld\n",ans,anss);
return 0;
}