今天我们队排名第四,然后总排排第6,勉强站住了区域赛的位置,还有12天,要继续加油啊
B题:(Tarjan||暴力)
题意:
有一幅图,然后问你这幅图里面有多少个子图满足图的两个部分是完全对称的,而且这两个图要是完全图
解法:
由于最大为1e5,所以可以考虑直接暴力枚举每条边,之后从这两条边dfs下去,看它左右两边的子图是否对称
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 const int maxn = 100 + 5; 7 vector<int>g[maxn]; 8 int vis[maxn]; 9 int sz1, num1, sz2, num2; 10 11 void dfs(int u,int v,int &sz,int &num) { 12 num += g[u].size(); sz += 1; 13 vis[u] = 1; 14 for (int k=0; k < g[u].size(); k++) { 15 if (vis[g[u][k]])continue; 16 if (g[u][k] == v)continue; 17 dfs(g[u][k], v, sz, num); 18 } 19 } 20 21 int main() { 22 int T; scanf("%d", &T); 23 int kase = 0; 24 while (T--) { 25 int n, m; scanf("%d%d", &n, &m); 26 for (int i = 0; i <= n; i++) g[i].clear(); 27 28 for (int i = 0; i < m; i++) { 29 int u, v; scanf("%d%d", &u, &v); 30 g[u].push_back(v); 31 g[v].push_back(u); 32 } 33 34 int ans = 0; 35 for (int u = 1; u <= n; u++) { 36 for (int v = 0; v < g[u].size(); v++) { 37 sz1 = sz2 = num1 = num2 = 0; 38 39 memset(vis, 0, sizeof(vis)); 40 dfs(u, g[u][v], sz1, num1); 41 42 memset(vis, 0, sizeof(vis)); 43 dfs(g[u][v], u, sz2, num2); 44 45 if (sz1 == sz2&&num1 == num2) 46 if (num1 == sz1*(sz1 - 1) + 1) 47 ans++; 48 } 49 } 50 printf("Case #%d: %d\n", ++kase, ans/2); 51 } 52 return 0; 53 }
E题:(并查集)
题意:
有一个图,输出为n个数字, 表示第i个元素的父亲节点为 ,接下来q次有两种询问,第一种是删除结点 i 和它的父节点,还有一种是问你两个节点是否连通
解法:
并查集解即可
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 int set[1000000]; 6 7 int findSet(int x) { 8 if (x == set[x]) return x; 9 int tmp= findSet(set[x]); 10 return tmp; 11 } 12 13 void unionSet(int x, int y) { 14 int fx = findSet(x); 15 int fy = findSet(y); 16 if (fx != fy) { 17 set[fx] = fy; 18 } 19 } 20 21 22 int main() { 23 int T; scanf("%d", &T); 24 int kase = 1; 25 while (T--) { 26 memset(set, 0, sizeof(set)); 27 int n, q; scanf("%d%d", &n, &q); 28 for (int i = 1; i <= n; i++) { 29 scanf("%d", &set[i]); 30 if (set[i] == 0)set[i] = i; 31 } 32 33 printf("Case #%d:\n", kase++); 34 for (int i = 0; i < q; i++) { 35 getchar(); char c; scanf("%c", &c); 36 if (c == 'C') { 37 int f; scanf("%d", &f); 38 set[f] = f; 39 } 40 else if (c == 'Q') { 41 int a, b; scanf("%d%d", &a, &b); 42 if (findSet(a) == findSet(b))printf("YES\n"); 43 else printf("NO\n"); 44 } 45 } 46 } 47 return 0; 48 }
G: (不懂)
题意:
给你n盏灯,你有k个质数开关,每个质数开关可以控制是它的倍数的灯,每盏灯被打开奇数次才会亮,问如何控制开关使得亮的灯泡最多
解法:
对于<31的质数开关,直接暴力枚举所有状态,对于>=31的开关(任意两个>=31的质数开关不可能共同控制同一盏灯),就贪心一下,如果把它开起来能激活更多的灯,就开,否则就关。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 #include<string> 7 #include<cmath> 8 #include<map> 9 #include<set> 10 #include<vector> 11 #include<queue> 12 #include<string> 13 #include<bitset> 14 #include<ctime> 15 #include<deque> 16 #include<stack> 17 #include<functional> 18 #include<sstream> 19 typedef long long ll; 20 using namespace std; 21 typedef unsigned long long int ull; 22 #define maxn 200005 23 #define ms(x) memset(x,0,sizeof(x)) 24 #define Inf 0x7fffffff 25 #define inf 0x3f3f3f3f 26 const int mod = 1e9 + 7; 27 #define pi acos(-1.0) 28 #define pii pair<int,int> 29 #define eps 1e-5 30 #define pll pair<ll,ll> 31 #define lson 2*x 32 #define rson 2*x+1 33 34 int vis[maxn]; 35 int t, n, k; 36 37 void Find(int &res, int x) { 38 int i, j; 39 for (i = x; i <= n; i += x) { 40 if (vis[i] == 1)vis[i] = 0; 41 else vis[i] = 1; 42 if (vis[i])res++; 43 else res--; 44 } 45 } 46 47 int main() { 48 scanf("%d", &t); 49 int cnt = 0; 50 51 while (t--) { 52 cnt++; 53 int i, j; 54 vector<int>ve1, ve2; 55 scanf("%d%d", &n, &k); 56 57 for (i = 1; i <= k; i++) { 58 int c; c = read(); 59 if (c < 29)ve1.push_back(c); 60 else ve2.push_back(c); 61 } 62 63 int maxx = 0; 64 for (i = 0; i < (1 << ve1.size()); i++) { 65 int res = 0; 66 ms(vis); 67 68 for (j = 0; j < ve1.size(); j++) { 69 if ((1 << j)&i) { 70 Find(res, ve1[j]); 71 } 72 } 73 74 for (j = 0; j < ve2.size(); j++) { 75 int tmp = 0; 76 Find(tmp, ve2[j]); 77 res += max(0, tmp); 78 } 79 80 maxx = max(maxx, res); 81 } 82 //cout << maxx << endl; 83 printf("Case #%d: %d\n", cnt, maxx); 84 } 85 }
H题:(博弈dp)
题意:
有两支队,每只队都有n个人,一共有m个蛋糕,每个人至少吃一个,最多吃k个。
都采取最优策略,谁吃到最后一个蛋糕,那么那只队就胜利。
按照给定的顺序去吃蛋糕,问你最后谁胜利。
解法:
先缩点,把相同的点都缩成一个点。
那么就变成了ABABABA这样交替的形式了,然后跑DP就好了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const long long llINF = 9223372036854775807; 4 const int INF = 2147483647; 5 const int maxn = 1e3 + 7; 6 const double pi = acos(-1.0); 7 int t, n, m, k; 8 char s[maxn << 1]; 9 int dp[maxn << 1][maxn << 1]; 10 vector<int> v; 11 12 int dfs(int now, int rest) 13 { 14 if (dp[now][rest] != -1) 15 return dp[now][rest]; 16 if (rest <= v[now] * k) 17 return dp[now][rest] = 1; 18 dp[now][rest] = 0; 19 for (int i = v[now]; i <= k * v[now]; i++) 20 if (dfs(now + 1, rest - i) == 0) 21 return dp[now][rest] = 1; 22 return dp[now][rest]; 23 } 24 25 int main(int argc, char const *argv[]) 26 { 27 scanf("%d", &t); 28 for (int kase = 1; kase <= t; kase++) 29 { 30 scanf("%d%d%d", &n, &m, &k); 31 n *= 2; 32 memset(dp, -1, sizeof(dp)); 33 v.clear(); 34 35 scanf("%s", s + 1); 36 37 for (int i = 1; i <= n; i++) 38 { 39 int j = i + 1; 40 while (j <= n && s[j] == s[i]) 41 j++; 42 v.push_back(j - i); //每次的人数 43 i = j - 1; 44 } 45 46 printf("Case #%d: ", kase); 47 if (dfs(0, m)) 48 puts(s[1] == 'A' ? "A" : "B"); 49 else 50 puts(s[1] == 'A' ? "B" : "A"); 51 } 52 return 0; 53 } 54