2022 CCPC 广州站

链接

Link

B. Ayano and sequences

显然一共只有 $O(n)$ 个连续段。

那么对于所有连续段,他们产生的贡献是一个矩形内数的和。

对于时间 $i$ 的修改而言,其对时间 $j$ 的贡献是 $(j-i+1)\times w_i$。

于是用个数据结构维护一下修改产生的贡献,也即是维护一下 $w_i$ 和 $i\times w_i$ 的区间和就好了。

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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <bits/stdc++.h>
using namespace std;
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define VI vector<int>
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
template<class T>inline void read(T &x) {
x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) f|=(ch=='-');
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+(ch^48);
if(f) x=-x;
}
template<class T,class... V>
inline void read(T &a,V&... b){read(a); read(b...);}
#define CASES int ___;for(read(___);___--;)
mt19937 rnd(random_device{}());

const int N = 5e5+5;
ull ans[N];
#define lc (u<<1)
#define rc (lc|1)
#define ls lc,l,mid
#define rs rc,mid+1,r
ull s1[N<<2],s2[N<<2];
ull t1[N<<2],t2[N<<2];
inline void pushup(int u) {
s1[u] = s1[lc] + s1[rc];
s2[u] = s2[lc] + s2[rc];
}
inline void pushtag1(int u,int len,ull x) {
t1[u] += x;
s1[u] += x * len;
}
inline void pushtag2(int u,int len,ull x) {
t2[u] += x;
s2[u] += x * len;
}
inline void pushdown(int u,int l,int r) {
int mid = (l+r)>>1;
if(t1[u]) {
pushtag1(lc,mid-l+1,t1[u]);
pushtag1(rc,r-mid,t1[u]);
t1[u] = 0;
}
if(t2[u]) {
pushtag2(lc,mid-l+1,t2[u]);
pushtag2(rc,r-mid,t2[u]);
t2[u] = 0;
}
}
ull ask(int u,int l,int r,int L,int R,ull x) {
if(L<=l&&r<=R)
return s1[u] * x - s2[u];
pushdown(u,l,r);
int mid = (l+r)>>1;
ull ans = 0;
if(L<=mid)
ans += ask(ls,L,R,x);
if(mid<R)
ans += ask(rs,L,R,x);
return ans;
}
void add(int u,int l,int r,int L,int R,ull w,int p) {
if(L<=l&&r<=R) {
pushtag1(u,r-l+1,w);
pushtag2(u,r-l+1,1ull * w * p);
return;
}
pushdown(u,l,r);
int mid = (l+r)>>1;
if(L <= mid)
add(ls,L,R,w,p);
if(mid<R)
add(rs,L,R,w,p);
pushup(u);
}

struct node{
int l,r,c;
node() {}
node(int _l,int _r,int _c) {
l = _l; r = _r; c = _c;
}
friend inline bool operator<(const node &A,const node &B) {
if(A.l != B.l)
return A.l<B.l;
return A.r<B.r;
}
};
set<node> s;
int n,q;
int main() {
read(n,q);
fo(i,1,n) {
int x;
read(x);
s.insert({i,i,x});
}
s.insert({n+1,n+1,0});
fo(i,1,q) {
int opt,l,r; ull w;
read(opt,l,r,w);
if(opt == 1) {
auto it = s.upper_bound({l,n+1,0});
it --;
auto now = *it;
s.erase(it);
if(now.l != l)
s.insert({now.l,l-1,now.c});
s.insert({l,now.r,now.c});

it = s.upper_bound({r,n+1,0});
it --;
now = *it;
s.erase(it);
if(now.r != r)
s.insert({r+1,now.r,now.c});
s.insert({now.l,r,now.c});

auto it2 = it;
for(it = it2 = s.lower_bound({l,0,0});it != s.end() && it -> r <= r; it2++,s.erase(it),it = it2) {
now = *it;
ans[now.c] += ask(1,1,n,now.l,now.r,i-1);
}
s.insert({l,r,w});
ans[w] -= ask(1,1,n,l,r,i-1);
}
else
add(1,1,n,l,r,w,i-1);
}
for(auto [l,r,c]:s)
ans[c] += ask(1,1,n,l,r,q);
fo(i,1,n) {
printf("%llu ",ans[i]);
}
return 0;
}

C. Customs Controls 2

对于所有的点,其出边的所有势能和入边的所有势能都相同,那么这个点的权值等于出边势能-入边势能。

然后将相同势能的点用并查集合并起来,检查是否有环即可。

E. Elevator

按题意模拟就好。

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
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e5+5;
int a[N],id[N];
ll ans[N],m;
int n;
int c[N];
#define lowbit(x) ((x)&(-x))

inline void add(int x) {
for(;x<=n;x+=lowbit(x))
c[x]++;
}
inline int ask(int x,int ans = 0) {
for(;x;x-=lowbit(x))
ans+=c[x];
return ans;
}

int main() {
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
id[i]=i;
}
sort(id+1,id+n+1,[&](const int &x,const int &y){
if(a[x] != a[y]) {
return a[x] < a[y];
}
return x < y;
});
ll sum = 0;
for(int i=1;i<=n;i++) {
int u = id[i];
ans[u] = 1ll * (i-1) * a[u] - sum + ask(u);
sum += a[u];
add(u);
}
for(int i=1;i<=n;i++) {
if(ans[i] <= m-2)
printf("%lld\n",ans[i]);
else
printf("-1\n");
}
return 0;
}

H. GameX

按题意一个一个填上去即可。

I. Infection

一个有根的连通块的权值等于连通块内除根节点的 $p_i$ 的乘积乘根节点的 $a_u$ 乘上周围直接相邻的点的 $1-p_i$。

直接树形DP,记录节点的个数。

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
#include <bits/stdc++.h>
using namespace std;
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define VI vector<int>
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
template<class T>inline void read(T &x) {
x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) f|=(ch=='-');
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+(ch^48);
if(f) x=-x;
}
template<class T,class... V>
inline void read(T &a,V&... b){read(a); read(b...);}
#define CASES int ___;for(read(___);___--;)
mt19937 rnd(random_device{}());

const ll mod = 1e9+7;
inline ll Pow(ll x,int y) {
ll ans = 1;
for(;y;y>>=1,x=x*x%mod)
if(y&1)
ans=ans*x%mod;
return ans;
}

const int N = 2005;
int n;
vector<int> adj[N];
ll f[N][N],g[N][N],ans[N];
ll h[N],w[N];
ll a[N],p[N];
int siz[N];
void dfs(int u,int pre) {
siz[u] = 1;
g[u][1] = a[u]; f[u][1] = p[u];
for(int v:adj[u])
if(v != pre) {
dfs(v,u);
for(int i = 0; i <= siz[u]; i++)
for(int j = 0; j <= siz[v]; j++)
(h[i+j] += f[u][i] * f[v][j]) %= mod,
(w[i+j] += f[u][i] * g[v][j]) %= mod,
(w[i+j] += g[u][i] * f[v][j]) %= mod;
siz[u] += siz[v];
for(int i = 0; i <= siz[u]; i++)
f[u][i] = h[i], g[u][i] = w[i], h[i] = w[i] = 0;
}
fo(i,1,siz[u])
(ans[i] += g[u][i] * (pre ? (mod + 1 - p[pre]) : 1 )) %= mod;
f[u][0] = (mod + 1 - p[u]);
}

int main() {
ios::sync_with_stdio(0);
cin.tie(0);
read(n);
fo(i,2,n) {
int x,y;
read(x,y);
adj[x].pb(y); adj[y].pb(x);
}
ll sum = 0;
fo(i,1,n) {
int x;
read(a[i],p[i],x);
p[i] = p[i] * Pow(x,mod-2) % mod;
sum += a[i];
}
sum = Pow(sum,mod-2);
fo(i,1,n)
a[i] = a[i] * sum % mod;
dfs(1,0);
fo(i,1,n)
printf("%lld\n",ans[i]);
return 0;
}

J. Math Exam

解得:$a_1 = 1,a_{i+1} = a_i + 2$ 或 $-a_i$。

令 $b_i = \frac{|a_i+1|}{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
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
#include <bits/stdc++.h>
using namespace std;
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define VI vector<int>
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
template<class T>inline void read(T &x) {
x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) f|=(ch=='-');
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+(ch^48);
if(f) x=-x;
}
template<class T,class... V>
inline void read(T &a,V&... b){read(a); read(b...);}
#define CASES int ___;for(read(___);___--;)
mt19937 rnd(random_device{}());
const int N = 2e7+5;
const ll mod = 998244353;
inline ll Pow(ll x,int y) {
ll ans = 1;
for(;y;y>>=1,x=x*x%mod) if(y&1) ans = ans * x % mod;
return ans;
}
int fac[N],inv[N];
inline void init(int n) {
fac[0] = 1;
for(int i=1;i<=n;i++) fac[i] = 1ll * fac[i-1] * i % mod;
inv[n] = Pow(fac[n],mod-2);
for(int i=n;i>=1;i--) inv[i-1] = 1ll * inv[i] * i % mod;
}

inline ll C(int n,int m) {
if(n<0||m<0||n-m<0)
return 0;
return 1ll * fac[n] * inv[m] % mod * inv[n-m] % mod;
}
int n,m;

int x1,x2;
inline void update(int &x,int &y,int d) {
if(d == 1) {
swap(x,y);
x -= x1;
y += x1;
}
else {
swap(x,y);
x -= x2;
y += x2;
}
}

int main() {
read(n,m);
init(N-5);
int x,y,d;
x1 = -2,x2 = (m+1)/2;
ll ans = 0 ;
n--;
int nx,ny;
if(n&1)
nx = ((n+1)/2),ny = n - nx;
else
nx = n/2,ny = n/2;

fo(i,0,((m-1)/2+(n&1))/2) {
x = nx - i;
y = ny + i;
ans += C(x+y,y);
d = -1;
do {
update(x,y,d);
if(x<0||y<0)
break;
ans += C(x+y,y) * d;
d = -d;
}while(1);
x = nx - i;
y = ny + i;
d = -1;
do {
update(x,y,-d);
if(x<0||y<0)
break;
ans += C(x+y,y) * d;
d = -d;
}while(1);
}
printf("%lld\n",(ans%mod+mod)%mod);
return 0;
}

K. Middle Point Graph

设三元环个数为 $A$,四元环个数为 $B$,答案为:

$m\times (n+m-3) + \sum_{i=1}^n \binom{deg_i}{2} + 3A + B$。

时间复杂度 $O(m^ { 1.5 } )$。

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
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;

template<class T>inline void read(T &x) {
x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) f|=(ch=='-');
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+(ch^48);
if(f) x=-x;
}
const ll mod = 1e9+7;
const int N = 5e5+5;

int n,m;
vector<int> w[N],adj[N],vec[N];
int d[N];
ll ans;
int tmp[N];

void build(int n,int m) {
for(int i=1;i<=n;i++)
d[i]=0,
adj[i].clear(),vec[i].clear();
for(int i=1;i<=m;i++) {
int x,y;
read(x); read(y);
d[x]++; d[y]++;
adj[x].pb(y); adj[y].pb(x);
}
for(int i=1;i<=n;i++)
for(int j:adj[i])
if(d[i] > d[j] || (d[i] == d[j] && i > j))
vec[i].pb(j);
}

inline int Count3() {
int ans = 0;
for(int u=1;u<=n;u++) {
for(int v:vec[u])
tmp[v] = 1;
for(int v:vec[u])
for(int w:vec[v])
if(tmp[w])
ans++;
for(int v:vec[u])
tmp[v] = 0;
}
return ans;
}
inline ll Count4() {
ll ans = 0;
for(int u=1;u<=n;u++) {
for(int v:vec[u])
for(int w:adj[v])
if(d[u] > d[w] || (d[u] == d[w] && u > w)) {
ans += tmp[w];
tmp[w] ++;
}
for(int v:vec[u])
for(int w:adj[v])
tmp[w] = 0;
}
return ans;
}

int main() {
int T;
read(T);
for(;T--;) {
read(n); read(m);

build(n,m);

ans = 1ll * m * (n+m-3) % mod;
auto C2 = [&](const int &x) -> ll {
return 1ll*x*(x-1)/2;
};
for(int i=1;i<=n;i++)
(ans += 1ll * C2(d[i])) %= mod;

printf("%lld\n",( ans + Count3() * 3 + Count4() ) % mod );
}
return 0;
}

L. Station of Fate

签到题。

M. XOR Sum

对于某一位 $i$,其对 $n$ 有 $x(k-x)\times 2^i$ 的贡献。最大是 $81\times 2^i$。

那么考虑完第 $i$ 位以后,$n$ 中大于 $i+8$ 位的都要清零。

记录 $n$ 第 $i\sim i+7$ 位的情况,以及有多少个 $a_i$ 卡着上限,然后DP即可。

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
#include <bits/stdc++.h>
#define ll long long
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
using namespace std;

const ll mod = 1e9+7;
inline ll Pow(ll x,int y) {
ll ans = 1;
for(;y;y>>=1,x=x*x%mod) if(y&1) ans = ans * x % mod;
return ans;
}
const int N = 50;
ll fac[N],inv[N];
inline void init(int n) {
fac[0] = 1;
for(int i=1;i<=n;i++) fac[i] = fac[i-1] * i % mod;
inv[n] = Pow(fac[n],mod-2);
for(int i=n;i>=1;i--) inv[i-1] = inv[i] * i % mod;
}
inline ll C(int n,int m) {
return fac[n] * inv[m] % mod * inv[n-m] % mod;
}

ll n,m,k;
int n0[62],m0[62];
inline int bit_n(int b,int l) {
return (n>>b) & ((1ll<<l)-1);
}
ll f[51][19][(1<<8)+2];
ll dfs(int i,int cnt,int s) {
if(i == -1) {
if(s == 0)
return 1;
return 0;
}
if(f[i][cnt][s] != -1)
return f[i][cnt][s];
ll ans = 0;
int ns;
if(m0[i] == 0) {
int a1,b;
fo(a0,0,k-cnt) {
a1 = k-cnt-a0;
b = cnt;
ns = s - ((a0+b)*(a1));
if(ns&(1<<7)) continue;
ans += C(k-cnt,a0) * dfs(i-1,cnt,(ns<<1) | ((i==0?0:n0[i-1]))) % mod;
}
}
else {
int a1,b1;
fo(a0,0,k-cnt)
fo(b0,0,cnt) {
a1 = k-cnt-a0;
b1 = cnt-b0;
ns = s - ((a0+b0)*(a1+b1));
if(ns&(1<<7)) continue;
ans += C(k-cnt,a0) * C(cnt,b0) % mod * dfs(i-1,b1,(ns<<1) | ((i==0?0:n0[i-1]))) % mod;
}
}
return f[i][cnt][s] = ans % mod;
}
int main() {
init(49);
memset(f,-1,sizeof(f));
cin>>n>>m>>k;
fo(i,0,50)
n0[i] = (n>>i)&1,
m0[i] = (m>>i)&1;
printf("%lld\n",dfs(50,k,bit_n(50,8)));
return 0;
}