# 「PKUWC2018/PKUSC2018」试题选做

## 「PKUWC2018/PKUSC2018」试题选做

### loj2537 Minimax

#### code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int M = 1e9, N = 300005, mod = 998244353;
int a[N], rt[N], P, n, ans;
vector<int> g[N];
vector<pair<int, int> > Ans;
namespace Seg{
#define mid ((l + r) >> 1)
int s[N*30], tag[N*30], lc[N*30], rc[N*30], size;
inline void init(){ for(int i = 1; i < N * 30; i++) tag[i] = 1; }
inline void pushdown(int u){
if(tag[u] == 1) return;
if(lc[u]){
s[lc[u]] = 1ll * tag[u] * s[lc[u]] % mod;
tag[lc[u]] = 1ll * tag[lc[u]] * tag[u] % mod;
}
if(rc[u]){
s[rc[u]] = 1ll * tag[u] * s[rc[u]] % mod;
tag[rc[u]] = 1ll * tag[rc[u]] * tag[u] % mod;
}
tag[u] = 1;
}
inline void insert(int &u, int l, int r, int pos){
if(!u) u = ++size;
if(l == r) return (void) (s[u] = 1);
if(pos <= mid) insert(lc[u], l, mid, pos);
else insert(rc[u], mid + 1, r, pos);
s[u] = s[lc[u]] + s[rc[u]];
}
inline int merge(int x, int y, int sumx, int sumy){
if(!x){
if(!sumx) return y;
s[y] = 1ll * s[y] * sumx % mod;
tag[y] = 1ll * tag[y] * sumx % mod;
return y;
}
if(!y){
if(!sumy) return x;
s[x] = 1ll * s[x] * sumy % mod;
tag[x] = 1ll * tag[x] * sumy % mod;
return x;
}
pushdown(x), pushdown(y);
int o = ++size;
int Lx = (sumx + 1ll * P * s[lc[x]] % mod) % mod;
int Ly = (sumy + 1ll * P * s[lc[y]] % mod) % mod;
int Rx = (sumx + 1ll * (mod + 1 - P) * s[rc[x]] % mod) % mod;
int Ry = (sumy + 1ll * (mod + 1 - P) * s[rc[y]] % mod) % mod;
lc[o] = merge(lc[x], lc[y], Rx, Ry);
rc[o] = merge(rc[x], rc[y], Lx, Ly);
s[o] = (s[lc[o]] + s[rc[o]]) % mod;
return o;
}
inline void getans(int u, int l, int r){
if(l == r) return (void) Ans.push_back(make_pair(l, s[u]));
pushdown(u);
if(lc[u]) getans(lc[u], l, mid);
if(rc[u]) getans(rc[u], mid + 1, r);
}
}
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % mod)
if(b & 1) ans = 1ll * ans * a % mod;
return ans;
}
inline void dfs(int u){
if(!(int) g[u].size()) Seg::insert(rt[u], 1, M, a[u]);
for(int i = 0; i < (int) g[u].size(); i++){
dfs(g[u][i]);
P = a[u];
rt[u] = Seg::merge(rt[u], rt[g[u][i]], 0, 0);
}
}
int main(){
for(int i = 1, x; i <= n; i++) read(x), g[x].push_back(i);
for(int i = 1; i <= n; i++){
if((int) g[i].size()) a[i] = 1ll * a[i] * Pow(10000, mod1- 2) % mod;
}
Seg::init();
dfs(1), Seg::getans(rt[1], 1, M), sort(Ans.begin(), Ans.end());
for(int i = 0; i < (int) Ans.size(); i++){
(ans += 1ll * (i + 1) * Ans[i].first % mod * Ans[i].second % mod * Ans[i].second % mod) %= mod;
}
cout << ans << endl;
return 0;
}   

### loj2538 Slay the Spire

$f[i][j]$ 表示前 $i$ 张强化牌摸了 $j$ 张的期望加成，从大到小对强化牌排序，枚举当前这张牌是否被摸到来转移。

$g[i][j]$ 表示前 $i$ 张攻击牌摸了 $j$ 张的期望攻击力之和，$j$ 越大可以打的攻击牌越多，所以从小到大排序来转移。

#### code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 3005, mod = 998244353;
int a[N], b[N], js[N], inv[N], f[2][N], g[2][N], n, m, k;
inline void up(int &x, int y){
x = (x + y >= mod ? x + y - mod : x + y);
}
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % mod)
if(b & 1) ans = 1ll * ans * a % mod;
return ans;
}
inline int C(int x, int y){
return 1ll * js[x] * inv[y] % mod * inv[x-y] % mod;
}
inline void solve(){
for(int i = 1; i <= n; i++) read(a[i]);
for(int i = 1; i <= n; i++) read(b[i]);
sort(a + 1, a + n + 1, greater<int>());
sort(b + 1, b + n + 1);
for(int i = 0; i <= n; i++)
f[0][i] = f[1][i] = g[0][i] = g[1][i] = 0;
f[0][0] = 1;
for(int i = 1, o = 1; i <= n; i++, o ^= 1){
for(int j = 0; j <= i; j++){
f[o][j] = f[o^1][j];
if(j && j < k) up(f[o][j], 1ll * a[i] * f[o^1][j-1] % mod);
else if(j) up(f[o][j], f[o^1][j-1]);
}
}
for(int i = 1, o = 1; i <= n; i++, o ^= 1){
for(int j = 0; j <= i; j++){
g[o][j] = g[o^1][j];
if(j){
if(m - j < k - 1) up(g[o][j], g[o^1][j-1]);
up(g[o][j], 1ll * C(i - 1, j - 1) * b[i] % mod);
}
}
}
int ans = 0;
for(int i = 0; i <= min(m, n); i++)
if(m - i <= n) up(ans, 1ll * f[n&1][i] * g[n&1][m-i] % mod);
printf("%d\n", ans);
}
int main(){
js[0] = inv[0] = 1;
for(int i = 1; i < N; i++)
js[i] = 1ll * js[i-1] * i % mod, inv[i] = Pow(js[i], mod - 2);
return 0;
}

### loj2540 随机算法

#### code

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int mod = 998244353;
int cnt[1<<21], dp[1<<21][21], js[21], inv[21], ed[21], n, m;
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % mod)
if(b & 1) ans = 1ll * ans * a % mod;
return ans;
}
inline int A(int x, int y){
return 1ll * js[x] * inv[x-y] % mod;
}
inline void up(int &x, int y){
x = (x + y >= mod ? x + y - mod : x + y);
}
int main(){
js[0] = inv[0] = 1;
for(int i = 1; i <= n; i++){
js[i] = 1ll * js[i-1] * i % mod;
inv[i] = Pow(js[i], mod - 2);
}
for(int i = 1, x, y; i <= m; i++){
ed[x] |= 1 << (y - 1);
ed[y] |= 1 << (x - 1);
}
for(int s = 0; s < (1 << n); s++)
for(int i = 0; i < n; i++)
if((1 << i) & s) cnt[s]++;
dp[0][0] = 1;
for(int s = 0; s < (1 << n) - 1; s++)
for(int i = 0; i < n; i++) if(dp[s][i]){
for(int j = 0; j < n; j++) if(!((1 << j) & s)){
int t = s | (1 << j) | ed[j+1];
up(dp[t][i+1], 1ll * dp[s][i] * A(n - cnt[s] - 1, cnt[s^t] - 1) % mod);
}
}
int mx = 0;
for(int i = 1; i <= n; i++) if(dp[(1<<n)-1][i]) mx = i;
cout << 1ll * dp[(1<<n)-1][mx] * inv[n] % mod << endl;
return 0;
}

### loj2542 随机游走

$dp[x][s]$ 为从 $x$ 出发走到点集 $s$ 中任意一个点的期望步数，然后 $\min-\max$ 容斥即可 ，直接分层图+高斯消元跑不过去，可以用小套路把未知数设出来以后每个点都可以用其父亲的答案乘上一个系数再加上一个常数来表示，然后跑一遍树形dp就做完了。

#### code

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 1 << 21, mod = 998244353;
vector<int> g[N];
int mn[N], cnt[N], in[N], A[N], B[N], n, q, rt;
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % mod)
if(b & 1) ans = 1ll * ans * a % mod;
return ans;
}
inline void dfs(int u, int fa){
if(in[u]) return (void) (A[u] = B[u] = 0);
int SA = 0, SB = 0, deg = (int) g[u].size();
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i];
if(v == fa) continue;
dfs(v, u);
SA = (SA + A[v]) % mod, SB = (SB + B[v]) % mod;
}
deg = Pow(deg, mod - 2);
int x = (1 - 1ll * SA * deg % mod + mod) % mod;
x = Pow(x, mod - 2);
A[u] = 1ll * deg * x % mod;
B[u] = 1ll * x * (1ll * SB * deg % mod + 1) % mod;
}
int main(){
for(int i = 1, x, y; i < n; i++){
g[x].push_back(y), g[y].push_back(x);
}
for(int s = 0; s < (1 << n); s++){
for(int i = 1; i <= n; i++){
in[i] = ((1 << (i - 1)) & s) ? 1 : 0;
cnt[s] += in[i];
}
dfs(rt, 0), mn[s] = B[rt];
}
while(q--){
int num, sta = 0;
for(int i = 1, x; i <= num; i++) read(x), sta |= 1 << (x - 1);
int ans = 0;
for(int s = sta; s; s = (s - 1) & sta)
(ans += 1ll * ((cnt[s] & 1) ? 1 : mod - 1) * mn[s] % mod) %= mod;
printf("%d\n", ans);
}
return 0;
}   

### loj6432 真实排名

#### code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define fi first
#define se second
const int N = 1000005, mod = 998244353;
pair<int, int> a[N];
int js[N], inv[N], ans[N], n, k;
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % mod)
if(b & 1) ans = 1ll * ans * a % mod;
return ans;
}
inline int C(int x, int y){
if(x < y || x < 0 || y < 0) return 0;
return 1ll * js[x] * inv[y] % mod * inv[x-y] % mod;
}
int main(){
js[0] = inv[0] = 1;
for(int i = 1; i <= n; i++){
js[i] = 1ll * js[i-1] * i % mod;
inv[i] = Pow(js[i], mod - 2);
}
sort(a + 1, a + n + 1);
int p = 0, q = 0;
for(int i = 1; i <= n; i++){
if(a[i].fi == a[i-1].fi && i > 1){
ans[a[i].se] = ans[a[i-1].se];
continue;
}
while(a[p+1].fi * 2 < a[i].fi && p < n) p++;
while(a[q+1].fi < a[i].fi * 2 && q < n) q++;
int tot1 = i - p - 1, tot2 = max(q, i) - i + 1;
(ans[a[i].se] += C(n - tot1 - 1, k)) %= mod;
(ans[a[i].se] += C(n - tot2, k - tot2)) %= mod;
}
for(int i = 1; i <= n; i++) printf("%d\n", ans[i]);
return 0;
}   

### loj6433 最大前缀和

#### code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = (1 << 20), mod = 998244353;
int a[N], f[N], sum[N], g[N], n;
inline void up(int &x, int y){
x = x + y >= mod ? x + y - mod : x + y;
}
int main(){
for(int i = 1; i <= n; i++) read(a[i]);
for(int s = 1; s < (1 << n); s++)
for(int i = 0; i < n; i++)
if((1 << i) & s) sum[s] += a[i+1];
g[0] = 1;
for(int i = 0; i < n; i++) f[1<<i] = 1;
for(int s = 0; s < (1 << n); s++)
for(int i = 0; i < n; i++) if(!((1 << i) & s)){
int t = s ^ (1 << i);
if(sum[s] > 0) up(f[t], f[s]);
if(sum[t] <= 0) up(g[t], g[s]);
}
int ans = 0;
for(int s = 0; s < (1 << n); s++){
sum[s] = (sum[s] % mod + mod) % mod;
up(ans, 1ll * sum[s] * f[s] % mod * g[((1<<n)-1)^s] % mod);
}
cout << ans << endl;
return 0;
}

### loj6436 星际穿越

#### code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 300005;
ll a[N], f[N][21], s[N][21];
int n, q;
inline ll calc(int x, int L){
if(a[x] <= L) return x - L;
ll ans = x - a[x], now = 1; x = a[x];
for(int i = 20; ~i; i--) if(f[x][i] >= L){
ans += s[x][i] + (x - f[x][i]) * now;
now += 1 << i, x = f[x][i];
}
return ans + (x - L) * (now + 1);
}
int main(){
for(int i = 2; i <= n; i++) read(a[i]);
for(int i = n; i >= 1; i--){
f[i][0] = min(a[i], i == n ? inf : f[i+1][0]);
s[i][0] = i - f[i][0];
}
for(int j = 1; j <= 20; j++)
for(int i = 1; i <= n; i++){
f[i][j] = f[f[i][j-1]][j-1];
s[i][j] = s[i][j-1] + s[f[i][j-1]][j-1];
s[i][j] += (f[i][j-1] - f[f[i][j-1]][j-1]) << (j - 1);
}
for(int i = 1, l, r, x; i <= q; i++){
ll ans = calc(x, l) - calc(x, r + 1);
ll g = __gcd(ans, (ll) r - l + 1);
printf("%lld/%lld\n", ans / g, (r - l + 1) / g);
}
return 0;
}   

### loj6436 神仙的游戏

border有关的计数题可以从等差数列和周期两个角度考虑，这个题显然不能等差数列于是就直接上周期定理。

#### code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = (1 << 22), P = 998244353, G = 3;
char s[N];
int a[N], b[N];
namespace poly{
int rev[N], lg, len;
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % P)
if(b & 1) ans = 1ll * ans * a % P;
return ans;
}
inline void timesinit(int lenth){
for(len = 1, lg = 0; len <= lenth; len <<= 1, lg++);
for(int i = 0; i < len; i++)
rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (lg - 1));
}
inline void dft(int *a, int sgn){
for(int i = 0; i < len; i++)
if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int k = 2; k <= len; k <<= 1){
int w = Pow(G, (P - 1) / k);
if(sgn == - 1) w = Pow(w, P - 2);
for(int i = 0; i < len; i += k){
int now = 1;
for(int j = i; j < i + (k >> 1); j++){
int x = a[j], y = 1ll * a[j+(k>>1)] * now % P;
a[j] = x + y >= P ? x + y - P : x + y;
a[j+(k>>1)] = x - y < 0 ? x - y + P : x - y;
now = 1ll * now * w % P;
}
}
}
if(sgn == -1){
int Inv = Pow(len, P - 2);
for(int i = 0; i < len; i++)
a[i] = 1ll * a[i] * Inv % P;
}
}
}
using poly::timesinit;
using poly::dft;
int main(){
scanf("%s", s); int n = strlen(s);
for(int i = 0; i < n; i++)
a[i] = s[i] == '0', b[i] = s[i] == '1';
reverse(b, b + n);
timesinit(n + n - 1);
dft(a, 1), dft(b, 1);
for(int i = 0; i < poly::len; i++)
a[i] = 1ll * a[i] * b[i] % P;
dft(a, -1);
ll ans = 1ll * n * n;
for(int i = 1; i < n; i++){
int flag = 0;
for(int j = i; j < n; j += i)
if(a[n-1+j] || a[n-1-j]) flag = 1;
if(!flag) ans ^= 1ll * (n - i) * (n - i);
}
cout << ans << endl;
return 0;
}
posted @ 2019-05-07 10:29 Joyemang33 阅读(...) 评论(...) 编辑 收藏