Gym - 102222、2018宁夏邀请赛、2019银川icpc网络预选赛
current: 10 / 13
?A. Maximum Element In A Stack
?B. Rolling The Polygon
?C. Caesar Cipher
?D. Take Your Seat
E. 2-3-4 Tree
模拟题
// #pragma GCC optimize(2) // #pragma GCC optimize(3) // #pragma GCC optimize(4) #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> #include <unordered_set> // #include<bits/extc++.h> // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9+7; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ const int maxn = 5009; int tot; struct node{ int cnt; int val[3]; int son[4]; } tree[maxn *2]; int newnode() { ++tot; tree[tot].cnt = 0; for(int i=0; i<3; i++) tree[tot].val[i] = 0; for(int i=0; i<4; i++) tree[tot].son[i] = 0; return tot; } void insert(int p, int val) { int id = tree[p].cnt; for(int i = 0; i < tree[p].cnt; i++) { if(val < tree[p].val[i]) { id = i; break; } } int flag = 1; for(int i=0; i <= tree[p].cnt; i++) if(tree[p].son[i]) flag = 0; if(flag) { int cur = tree[p].cnt; while(cur > id) tree[p].val[cur] = tree[p].val[cur-1], cur--; tree[p].val[id] = val; tree[p].cnt++; return; } if(tree[p].son[id] == 0) tree[p].son[id] = newnode(); int np = tree[p].son[id]; if(tree[np].cnt == 3) { int cur = tree[p].cnt; while(cur > id) tree[p].val[cur] = tree[p].val[cur-1], cur--; tree[p].val[id] = tree[np].val[1]; tree[p].cnt++; int lp = newnode(); tree[np].cnt = 1; tree[lp].cnt = 1; tree[lp].val[0] = tree[np].val[2]; tree[lp].son[0] = tree[np].son[2]; tree[lp].son[1] = tree[np].son[3]; cur = tree[p].cnt; while(cur > id + 1) tree[p].son[cur] = tree[p].son[cur-1], cur--; tree[p].son[id+1] = lp; tree[p].son[id] = np; if(val > tree[np].val[1]) np = lp; } insert(np,val); } void display(int p) { if(tree[p].cnt == 0) return; for(int i=0; i<tree[p].cnt; i++) { printf("%d ", tree[p].val[i]); } puts(""); for(int i=0; i<=tree[p].cnt; i++) { display(tree[p].son[i]); } } int main(){ int T; scanf("%d", &T); int cas = 0; while(T--) { tot = 0; int rt = newnode(); int n; scanf("%d", &n); for(int i=1; i<=n; i++) { int x; scanf("%d", &x); if(tree[rt].cnt == 3) { int newle = rt; rt = newnode(); int newri = newnode(); tree[rt].cnt = 1; tree[rt].val[0] = tree[newle].val[1]; tree[rt].son[0] = newle; tree[rt].son[1] = newri; tree[newri].cnt = 1; tree[newri].val[0] = tree[newle].val[2]; tree[newri].son[0] = tree[newle].son[2]; tree[newri].son[1] = tree[newle].son[3]; tree[newle].cnt =1; } insert(rt, x); } printf("Case #%d:\n", ++cas); display(rt); } return 0; }
?F. Moving On
G. Factories
树形DP + 背包
https://blog.csdn.net/dllpXFire/article/details/81085093
https://blog.csdn.net/starlet_kiss/article/details/100176118
问题可以转化为边使用的贡献。
所以对于一个点u,在以u为根的子树中选了几个点,可以算出边的贡献。
// #pragma GCC optimize(2) // #pragma GCC optimize(3) // #pragma GCC optimize(4) #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> #include <unordered_set> // #include<bits/extc++.h> // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9+7; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ const int maxn = 1e5+9; vector<pii>mp[maxn]; int du[maxn]; ll dp[maxn][109]; int sz[maxn]; int n,k; bool cmp(pii a, pii b) { return sz[a.fi] < sz[b.fi]; } void dfs(int u, int fa) { for(int i=1; i<=k; i++) dp[u][i] = inff; dp[u][0] = 0; if(mp[u].size() == 1 ) { sz[u] = 1; dp[u][1] = 0; } else sz[u] = 0; for(pii p : mp[u]) { int v = p.fi, w = p.se; if(v == fa) continue; dfs(v, u); } sort(mp[u].begin(), mp[u].end(), cmp); //sort下, 快了5s。 for(pii p : mp[u]) { int v = p.fi, w = p.se; if(v == fa) continue; for(int i = min(k, sz[u]); i>=0; i--) { //i 表示目前有几个 for(int j=0; j<=min(k, sz[v]) &&i + j <= k; j++) {//j表示可以从子树中拿几个 dp[u][i + j] = min(dp[u][i+j], dp[v][j] + dp[u][i] + 1ll*w*j*(k-j)); } } sz[u] += sz[v]; } } int main(){ int T; scanf("%d", &T); int cas = 0; while(T--) { scanf("%d%d", &n, &k); for(int i=1; i<=n; i++) du[i] = 0, mp[i].clear(); for(int i=1; i<n; i++) { int u,v,w; scanf("%d%d%d", &u, &v, &w); mp[u].pb(pii(v, w)); mp[v].pb(pii(u, w)); du[u]++;du[v]++; } if(k == 1) { printf("Case #%d: %d\n", ++cas, 0); continue; } if(n == 2) { printf("Case #%d: %d\n", ++cas, mp[1][0].se); continue; } int rt = 1; for(int i=1; i<=n; i++) if(du[i] > 1) rt = i; dfs(rt, rt); printf("Case #%d: %lld\n", ++cas, dp[rt][k]); } return 0; }
?H. Fight Against Monsters
I. Bubble Sort
https://www.cnblogs.com/wzgg/p/11453284.html
J. Nested Triangles
K. Vertex Covers
折半枚举 + 高维前缀和(用sosDP枚举父集)
先处理出前半数点的情况,注意去掉不合法的状态。然后对每个状态累加上包含这种状态的父集的DP值。
然后枚举后半数点的情况,对于两半间的边,如果后半数点没选,前半数点就必选。累计答案即可。
// #pragma GCC optimize(2) // #pragma GCC optimize(3) // #pragma GCC optimize(4) #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> #include <unordered_set> // #include<bits/extc++.h> // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9+7; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ const int maxn = 50; int w[maxn], used[maxn]; vector<int>mp[maxn]; const int maxm = 1e6+9; ll dp[maxm]; int main(){ int T; scanf("%d", &T); int cas = 0; while(T--) { int n, m, q; scanf("%d%d%d", &n, &m, &q); for(int i=1; i<=n; i++) scanf("%d", &w[i]); for(int i=1; i<=m; i++) { int u,v; scanf("%d%d", &u, &v); mp[u].pb(v); mp[v].pb(u); } int Le = n / 2, Ri = n - Le; for(int i=0; i < (1 << Le); i++) { int x = i; ll tmp = 1; for(int j=1; j<=Le; j++) { used[j] = x % 2; x = x / 2; if(used[j]) tmp = tmp * w[j] % q; } int flag = 0; for(int j=1; j<=Le; j++) { if(used[j]) continue; int ff = 0; for(int v : mp[j]) { if(v <= Le && used[v] == 0) { ff = 1; break; } } if(ff) {flag = 1; break;} } if(flag) { dp[i] = 0; continue; } dp[i] = tmp; } // for (int mask = 0; mask < (1<<k); mask++) dp[mask] = cnt[mask]; ///用sosDP枚举每个状态的父集 for (int i = 0; i < Le; i++) { for (int mask = 0; mask < (1<<Le); mask++) { if(mask&(1<<i)) dp[mask^(1<<i)] = (dp[mask^(1<<i)] + dp[mask] ) % q; } } ll ans = 0; for(int i=0; i < (1 << Ri); i++) { int x = i; ll tmp = 1; for(int j=1; j<=Ri; j++) { int id = j + Le; used[id] = x % 2; x = x / 2; if(used[id]) tmp = tmp * w[id] % q; } int flag = 0; for(int j=1; j<=Ri; j++) { int id = j + Le; if(used[id]) continue; int ff = 0; for(int v : mp[id]) { if(v > Le && used[v] == 0) { ff = 1; break; } } if(ff) {flag = 1; break;} } if(flag) continue; int left = 0; for(int j=1; j<=Ri; j++) { int id = j + Le; if(used[id]) continue; for(int v : mp[id]) { if(v <= Le) { left = left | (1 << (v-1)); } } } // cout<< left << " , " << i<<endl; ans = (ans + dp[left] * tmp % q )% q; } printf("Case #%d: %lld\n",++cas, ans); for(int i=1; i<=n; i++) mp[i].clear(), used[i] = 0; } return 0; }
L. Continuous Intervals
单调栈 + 线段树
参考: https://blog.csdn.net/u013534123/article/details/81164504
首先要想到问题可以转化为求 满足 $max - min + 1 == cnt$ 的区间个数
其中max表示区间最大值,min表示区间最小值,cnt表示区间种类数。
对公式移项 得到$max - min - cnt == -1$。
于是可以枚举区间右端点,计算有多少左端点满足$max - min - cnt == -1$。
/* * @Author: chenkexing * @Date: 2019-09-01 21:08:33 * @Last Modified by: chenkexing * @Last Modified time: 2019-09-01 22:41:48 * @link:https://nanti.jisuanke.com/t/41296 */ #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> // #include<bits/extc++.h> // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ const int maxn = 1e5+9; int a[maxn]; stack<pii>sbig, ssml; map<int, int> pre; pii tree[maxn<<2]; int lazy[maxn << 2]; void pushup(int rt) { if(tree[rt<<1].fi == tree[rt<<1|1].fi) { tree[rt].fi = tree[rt<<1].fi; tree[rt].se = tree[rt<<1].se + tree[rt<<1|1].se; } else if(tree[rt<<1].fi < tree[rt<<1|1].fi) { tree[rt] = tree[rt<<1]; } else { tree[rt] = tree[rt<<1|1]; } } void build(int le, int ri, int rt) { lazy[rt] = 0; if(le == ri) { tree[rt] = pii(0, 1); return; } int mid = (le + ri) >> 1; build(le, mid ,rt<<1); build(mid+1, ri, rt<<1|1); pushup(rt); } void pushdown(int le, int ri,int rt) { lazy[rt<<1] += lazy[rt]; lazy[rt<<1|1] += lazy[rt]; tree[rt<<1].fi += lazy[rt]; tree[rt<<1|1].fi += lazy[rt]; lazy[rt] = 0; } void update(int L, int R, int val, int le, int ri, int rt) { if(le >= L && ri <= R) { lazy[rt] += val; tree[rt].fi += val; return; } int mid = (le + ri) >> 1; if(lazy[rt]) pushdown(le, ri, rt); if(mid >= L) update(L, R, val, le, mid, rt<<1); if(mid < R) update(L, R, val, mid+1, ri, rt<<1|1); pushup(rt); } pii query(int L, int R, int le, int ri, int rt) { if(le >= L && ri <= R) { return tree[rt]; } int mid = (le + ri) >> 1; pii res = pii(inf, inf); if(lazy[rt]) pushdown(le, ri, rt); if(mid >= L) { res = query(L, R, le, mid, rt<<1); } if(mid < R) { pii t = query(L, R, mid+1, ri, rt<<1|1); if(t.fi == res.fi) res.se += t.se; else if(t.fi < res.fi) res = t; } return res; } int main(){ int T; scanf("%d", &T); int cas = 0; while(T--) { int n; scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &a[i]); ll ans = 0; pre.clear(); build(1, n, 1); while(!sbig.empty()) sbig.pop(); while(!ssml.empty()) ssml.pop(); // sbig.push(pii(0, 0)); // ssml.push(pii(0, 0)); for(int i=1; i<=n; i++) { pii tmp = pii(0, 0); if(!sbig.empty()) tmp = sbig.top(); update(tmp.se+1, i, a[i], 1, n, 1); while(!sbig.empty() && sbig.top().fi <= a[i]) { pii tmp = sbig.top(); sbig.pop(); pii ff = pii(0, 0); if(!sbig.empty()) ff = sbig.top(); update(ff.se+1,tmp.se , a[i] - tmp.fi, 1, n, 1); } sbig.push(pii(a[i], i)); tmp = pii(0, 0); if(!ssml.empty()) tmp = ssml.top(); update(tmp.se+1, i, -a[i] , 1, n, 1); while(!ssml.empty() && ssml.top().fi >= a[i]) { pii tmp = ssml.top(); ssml.pop(); pii ff = pii(0, 0); if(!ssml.empty()) ff = ssml.top(); update(ff.se+1,tmp.se , tmp.fi - a[i] , 1, n, 1); } ssml.push(pii(a[i], i)); if(pre.count(a[i]) == false) pre[a[i]] = 0; update(pre[a[i]] + 1, i, -1, 1, n, 1); pre[a[i]] = i; pii t = query(1, i, 1, n, 1); if(t.fi == -1) ans += t.se; } printf("Case #%d: %lld\n", ++cas, ans); } return 0; }
M. Acyclic Orientation