最近做的一场比赛,把自己负责过的题目记一下好了。
Problem B URAL 2013 Neither shaken nor stirred
题意:一个有向图,每个结点一个非负值,可以转移到其他结点。初始时刻从结点出发,然后每次到达一个结点询问上一个到达的正值结点的权值,离开结点时也要询问一下,因为当前结点可能为正数,答案就是这个值了,如果不存在这个样的正权值输出“sober",或者不明确时输出“unkonwn”。
分析:可以当做树形dp来做。dp[u][0]表示进入结点时上一个正权值,dp[u][1]表示离开结点时的正权值, val[u]表示结点u权值,inf表示不明确情况。
转移这样来做:
对于边u->v,首先考虑dp[v][1], val[v] != 0时, dp[v][1] = val[v],否则dp[v][1] = dp[v][0]。
如果v没有访问过,dp[v][0] = dp[u][1], v访问过,那么dp[v][0] != dp[u][1]时,更新dp[v][0] = inf,并且 当val[v] = 0时,要从v点重新出发dfs, 因为此时dp[v][1]值也会变化。
代码:
1 #include <bits/stdc++.h> 2 #define pb push_back 3 #define mp make_pair 4 #define esp 1e-8 5 #define lowbit(x) ((x)&(-x)) 6 #define lson l, m, rt<<1 7 #define rson m+1, r, rt<<1|1 8 #define sz(x) ((int)((x).size())) 9 #define pb push_back 10 #define in freopen("solve_in.txt", "r", stdin); 11 #define out freopen("solve_out.txt", "w", stdout); 12 13 #define bug(x) printf("Line : %u >>>>>>\n", (x)); 14 #define inf 0x0f0f0f0f 15 using namespace std; 16 typedef long long LL; 17 typedef pair<int, int> PII; 18 typedef map<int, int> MPS; 19 const int maxn = 100000 + 100; 20 vector<int> g[maxn]; 21 int vis[maxn]; 22 int dp[maxn][2], val[maxn]; 23 void dfs(int u, int fa) { 24 if(vis[u]) { 25 if(dp[fa][1] != dp[u][0]) { 26 dp[u][0] = inf; 27 if(!val[u]) { 28 dp[u][1] = inf; 29 for(int i = 0; i < sz(g[u]); i++) { 30 int v = g[u][i]; 31 dfs(v, u); 32 } 33 } 34 } 35 return; 36 } 37 vis[u] = 1; 38 dp[u][0] = dp[fa][1]; 39 dp[u][1] = val[u] ? val[u] : dp[u][0]; 40 for(int i = 0; i < sz(g[u]); i++) { 41 int v = g[u][i]; 42 dfs(v, u); 43 } 44 } 45 int main() { 46 47 int n; 48 scanf("%d", &n); 49 for(int i = 1; i <= n; i++) { 50 int m; 51 scanf("%d%d", &val[i], &m); 52 for(int j = 0; j < m; j++) { 53 int u; 54 scanf("%d", &u); 55 g[i].pb(u); 56 } 57 } 58 vis[1] = 1; 59 dp[1][0] = 0; 60 dp[1][1] = val[1] ? val[1] : 0; 61 for(int i = 0; i < sz(g[1]); i++) { 62 int u = g[1][i]; 63 dfs(u, 1); 64 } 65 for(int i = 1; i <= n; i++) { 66 if(dp[i][0] == 0) 67 cout << "sober "; 68 else if(dp[i][0] == inf) 69 cout << "unknown "; 70 else cout << dp[i][0] << ' '; 71 if(dp[i][1] == 0) 72 cout << "sober\n"; 73 else if(dp[i][1] == inf) 74 cout << "unknown\n"; 75 else cout << dp[i][1] << endl; 76 } 77 return 0; 78 }
Problem C URAL 2014 Zhenya moves from parents
题意:共有n张收支凭据,根据当前的收到的凭据算出账户欠款,当前不足支出时,从账户扣除,收到一笔钱时把钱拿在手上不会去还信用卡上的钱,所以
信用卡欠款会越来越多的。
将时间离散化,排个序,然后以此建立线段树,每次将凭据对应的金额插入更新。线段树两个节点值,dep[rt],表示当前区间时账户欠款,tot[rt]表示当前区间时能够剩下的现金。具体更新:
dep[rt] = dep[rt<<1] + min(0LL, tot[rt<<1]+dep[rt<<1|1]);
tot[rt] = tot[rt<<1|1] + max(tot[rt<<1]+dep[rt<<1|1], 0LL);
代码:
1 #include <bits/stdc++.h> 2 #define pb push_back 3 #define mp make_pair 4 #define esp 1e-8 5 #define lowbit(x) ((x)&(-x)) 6 #define lson l, m, rt<<1 7 #define rson m+1, r, rt<<1|1 8 #define sz(x) ((int)((x).size())) 9 #define pb push_back 10 #define in freopen("solve_in.txt", "r", stdin); 11 #define out freopen("solve_out.txt", "w", stdout); 12 13 #define bug(x) printf("Line : %u >>>>>>\n", (x)); 14 #define inf 0x0f0f0f0f 15 using namespace std; 16 typedef long long LL; 17 typedef pair<int, int> PII; 18 typedef map<string, int> MPS; 19 const int maxn = 100000 + 100; 20 21 struct Node { 22 int mon, day, h, mi, c, id; 23 Node() {} 24 Node(int mon, int day, int h, int mi, int c, int id):mon(mon), day(day), h(h), mi(mi), c(c), id(id) {} 25 bool operator < (const Node &o)const { 26 if(mon == o.mon) { 27 if(day == o.day) { 28 if(h == o.h) return mi < o.mi; 29 return h < o.h; 30 } 31 return day < o.day; 32 } 33 return mon < o.mon; 34 } 35 } b[maxn]; 36 int a[maxn]; 37 char s[100]; 38 int pos[maxn]; 39 LL dep[maxn<<2], tot[maxn<<2]; 40 void PushUp(int rt) { 41 dep[rt] = dep[rt<<1] + min(0LL, tot[rt<<1]+dep[rt<<1|1]); 42 tot[rt] = tot[rt<<1|1] + max(tot[rt<<1]+dep[rt<<1|1], 0LL); 43 } 44 void update(int l, int r, int rt, int p, int c) { 45 if(p == l && p == r) { 46 if(c > 0) 47 tot[rt] = c; 48 else dep[rt] = c; 49 return; 50 } 51 int m = (l+r)>>1; 52 if(p <= m) 53 update(lson, p, c); 54 else update(rson, p, c); 55 PushUp(rt); 56 } 57 58 int main() { 59 60 int n; 61 scanf("%d", &n); 62 for(int i = 1; i <= n; i++) { 63 int c, day, mon, h, mi; 64 scanf("%d %d.%d %d:%d", &c, &day, &mon, &h, &mi); 65 b[i] = Node(mon, day, h, mi, c, i); 66 a[i] = c; 67 } 68 sort(b+1, b+n+1); 69 for(int i = 1; i <= n; i++) 70 pos[b[i].id] = i; 71 for(int i = 1; i <= n; i++) { 72 update(1, n, 1, pos[i], a[i]); 73 LL ans = dep[1]; 74 printf("%I64d\n", ans); 75 } 76 return 0; 77 }
Problem F URAL 2017 Best of a bad lot
题意:有n个人处在不同的位置,声称目击哪些人也在场,这些人中有一些是嫌疑人,但是他们为了洗脱嫌疑会让他们的证词不相互矛盾,而其他人则会说出真正的情况。问最小的嫌疑团体。
分析:2个人所在地方不同,但是都目击同一个人,那么这两个人必定有一个为嫌疑人,很显然可以建立一个二分图,每次给图中结点着色,选取最少的加入到答案中。
代码:
1 #include <bits/stdc++.h> 2 #define pb push_back 3 #define mp make_pair 4 #define esp 1e-8 5 #define lowbit(x) ((x)&(-x)) 6 #define lson l, m, rt<<1 7 #define rson m+1, r, rt<<1|1 8 #define sz(x) ((int)((x).size())) 9 #define pb push_back 10 #define in freopen("solve_in.txt", "r", stdin); 11 #define out freopen("solve_out.txt", "w", stdout); 12 13 #define bug(x) printf("Line : %u >>>>>>\n", (x)); 14 #define inf 0x0f0f0f0f 15 using namespace std; 16 typedef long long LL; 17 typedef pair<int, int> PII; 18 typedef map<string, int> MPS; 19 20 const int maxn = 444; 21 typedef set<int> :: iterator IT; 22 23 vector<int>g[maxn]; 24 set<int> a[maxn]; 25 vector<string> name; 26 27 int vis[maxn]; 28 vector<int> tmp[2]; 29 void dfs(int u, int col) { 30 tmp[col].pb(u); 31 vis[u] = 1; 32 for(int i = 0; i < sz(g[u]); i++) { 33 int v = g[u][i]; 34 if(vis[v]) continue; 35 dfs(v, col^1); 36 } 37 } 38 int main() { 39 40 int n; 41 scanf("%d", &n); 42 for(int i = 1; i <= n; i++) { 43 string str; 44 cin >> str; 45 name.pb(str); 46 int m; 47 scanf("%d", &m); 48 for(int j = 0; j < m; j++) { 49 int k; 50 scanf("%d", &k); 51 a[i].insert(k); 52 } 53 a[i].insert(i); 54 } 55 for(int i = 1; i <= n; i++) { 56 for(int j = i+1; j <= n; j++) { 57 if(name[i-1] != name[j-1]) { 58 for(IT it = a[i].begin(); it != a[i].end(); it++) 59 if(a[j].count(*it)) { 60 g[i].pb(j); 61 g[j].pb(i); 62 break; 63 } 64 } 65 } 66 } 67 vector<int> ans; 68 for(int i = 1; i <= n; i++) { 69 if(vis[i] || sz(g[i]) == 0) continue; 70 tmp[0].clear(); 71 tmp[1].clear(); 72 dfs(i, 0); 73 if(tmp[0].size() > tmp[1].size()) tmp[0] = tmp[1]; 74 for(int j = 0; j < sz(tmp[0]); j++) 75 ans.pb(tmp[0][j]); 76 } 77 if(sz(ans)) { 78 cout << sz(ans) << endl; 79 for(int i = 0; i < ans.size(); i++) 80 printf("%d%c", ans[i], i == sz(ans)-1 ? '\n' : ' '); 81 } else { 82 puts("1"); 83 puts("1"); 84 } 85 return 0; 86 }
Problem G URAL 2018 The Debut Album
题意:每个元素可以为1,或2,组成n个元素的排列,且连续1的个数不能超过a,连续2的个数不能超过b问有多少种方式.
分析:dp[now][0][len],表示当前位为1,前面已经有len个连续1了,
转移:dp[now][0][len] = dp[pre][0][len-1],len > 1
dp[now][0][len] = sum{dp[pre][1][k]| 1 <= k <= b},len == 1
当前位为0时同理。
代码:
1 #include <bits/stdc++.h> 2 #define pb push_back 3 #define mp make_pair 4 #define esp 1e-8 5 #define lowbit(x) ((x)&(-x)) 6 #define lson l, m, rt<<1 7 #define rson m+1, r, rt<<1|1 8 #define sz(x) ((int)((x).size())) 9 #define pb push_back 10 #define in freopen("solve_in.txt", "r", stdin); 11 #define out freopen("solve_out.txt", "w", stdout); 12 13 #define bug(x) printf("Line : %u >>>>>>\n", (x)); 14 #define inf 0x0f0f0f0f 15 using namespace std; 16 typedef long long LL; 17 typedef pair<int, int> PII; 18 typedef map<int, int> MPS; 19 const int maxn = 50000 + 100; 20 const int M = (int)1e9 + 7; 21 LL dp[2][2][310]; 22 int main() { 23 24 int n, a, b; 25 scanf("%d%d%d", &n, &a, &b); 26 dp[1][1][1] = dp[1][0][1] = 1; 27 for(int i = 2; i <= n; i++) { 28 int now = i&1; 29 int pre = 1^now; 30 31 for(int j = 1; j <= a; j++) { 32 dp[now][0][j] = 0; 33 if(j == 1) { 34 for(int k = 1; k <= b; k++) 35 dp[now][0][j] = (dp[now][0][j] + dp[pre][1][k])%M; 36 } else 37 dp[now][0][j] = (dp[now][0][j] + dp[pre][0][j-1])%M; 38 } 39 for(int j = 1; j <= b; j++) { 40 dp[now][1][j] = 0; 41 if(j == 1) { 42 for(int k = 1; k <= a; k++) 43 dp[now][1][j] = (dp[now][1][j] + dp[pre][0][k])%M; 44 } else 45 dp[now][1][j] = (dp[now][1][j] + dp[pre][1][j-1])%M; 46 } 47 } 48 LL ans = 0; 49 int now = n&1; 50 for(int i = 1; i <= a; i++) 51 ans = (ans + dp[now][0][i])%M; 52 for(int i = 1; i <= b; i++) 53 ans = (ans + dp[now][1][i])%M; 54 cout << ans << endl; 55 return 0; 56 }
Problem H URAL 2019 Pair: normal and paranormal
题意:括号匹配
分析:多重括号匹配,每种字母代表一个,A只能和a匹配。
代码:
Problem J URAL 2021 Scarily interesting!
题意:安排两个队伍n场比赛的得分,使得悬念保持的越长越好。
分析:赢的那方从小到大,另一方从大到小。
代码:
1 #include <bits/stdc++.h> 2 #define pb push_back 3 #define mp make_pair 4 #define esp 1e-8 5 #define lowbit(x) ((x)&(-x)) 6 #define lson l, m, rt<<1 7 #define rson m+1, r, rt<<1|1 8 #define sz(x) ((int)((x).size())) 9 #define pb push_back 10 #define in freopen("solve_in.txt", "r", stdin); 11 #define out freopen("solve_out.txt", "w", stdout); 12 13 #define bug(x) printf("Line : %u >>>>>>\n", (x)); 14 #define inf 0x0f0f0f0f 15 using namespace std; 16 typedef long long LL; 17 typedef pair<int, int> PII; 18 typedef map<int, int> MPS; 19 const int maxn = 1111; 20 int a[maxn], b[maxn], r1[maxn], r2[maxn]; 21 bool cmp1(int x, int y) { 22 return a[x] > a[y]; 23 } 24 bool cmp2(int x, int y) { 25 return b[x] > b[y]; 26 } 27 int main() { 28 29 int n; 30 scanf("%d", &n); 31 int sum1 = 0, sum2 = 0; 32 for(int i = 1; i <= n; i++) { 33 scanf("%d", &a[i]); 34 sum1 += a[i]; 35 r1[i] = i; 36 } 37 for(int i = 1; i <= n; i++) { 38 scanf("%d", b+i); 39 sum2 += b[i]; 40 r2[i] = i; 41 } 42 sort(r1+1, r1+n+1, cmp1); 43 sort(r2+1, r2+n+1, cmp2); 44 if(sum1 > sum2) { 45 for(int i = 1; i <= n; i++) 46 printf("%d %d\n", r1[n+1-i], r2[i]); 47 } else if(sum1 < sum2) { 48 for(int i = 1; i <= n; i++) 49 printf("%d %d\n", r1[i], r2[n+1-i]); 50 } else { 51 for(int i = 1; i <= n; i++) 52 printf("%d %d\n", i, i); 53 } 54 return 0; 55 }