今天我们队排名第四,然后总排排第6,勉强站住了区域赛的位置,还有12天,要继续加油啊
8.13场地址
B题:(Tarjan||暴力)
题意:
有一幅图,然后问你这幅图里面有多少个子图满足图的两个部分是完全对称的,而且这两个图要是完全图
解法:
由于最大为1e5,所以可以考虑直接暴力枚举每条边,之后从这两条边dfs下去,看它左右两边的子图是否对称
#include
#include
#include
#include
using namespace std;
const int maxn = 100 + 5;
vectorg[maxn];
int vis[maxn];
int sz1, num1, sz2, num2;
void dfs(int u,int v,int &sz,int &num) {
num += g[u].size(); sz += 1;
vis[u] = 1;
for (int k=0; k < g[u].size(); k++) {
if (vis[g[u][k]])continue;
if (g[u][k] == v)continue;
dfs(g[u][k], v, sz, num);
}
}
int main() {
int T; scanf("%d", &T);
int kase = 0;
while (T--) {
int n, m; scanf("%d%d", &n, &m);
for (int i = 0; i <= n; i++) g[i].clear();
for (int i = 0; i < m; i++) {
int u, v; scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
int ans = 0;
for (int u = 1; u <= n; u++) {
for (int v = 0; v < g[u].size(); v++) {
sz1 = sz2 = num1 = num2 = 0;
memset(vis, 0, sizeof(vis));
dfs(u, g[u][v], sz1, num1);
memset(vis, 0, sizeof(vis));
dfs(g[u][v], u, sz2, num2);
if (sz1 == sz2&&num1 == num2)
if (num1 == sz1*(sz1 - 1) + 1)
ans++;
}
}
printf("Case #%d: %d\n", ++kase, ans/2);
}
return 0;
}
E题:(并查集)
题意:
有一个图,输出为n个数字, 表示第i个元素的父亲节点为 ,接下来q次有两种询问,第一种是删除结点 i 和它的父节点,还有一种是问你两个节点是否连通
解法:
并查集解即可
#include
#include
#include
using namespace std;
int set[1000000];
int findSet(int x) {
if (x == set[x]) return x;
int tmp= findSet(set[x]);
return tmp;
}
void unionSet(int x, int y) {
int fx = findSet(x);
int fy = findSet(y);
if (fx != fy) {
set[fx] = fy;
}
}
int main() {
int T; scanf("%d", &T);
int kase = 1;
while (T--) {
memset(set, 0, sizeof(set));
int n, q; scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) {
scanf("%d", &set[i]);
if (set[i] == 0)set[i] = i;
}
printf("Case #%d:\n", kase++);
for (int i = 0; i < q; i++) {
getchar(); char c; scanf("%c", &c);
if (c == 'C') {
int f; scanf("%d", &f);
set[f] = f;
}
else if (c == 'Q') {
int a, b; scanf("%d%d", &a, &b);
if (findSet(a) == findSet(b))printf("YES\n");
else printf("NO\n");
}
}
}
return 0;
}
G: (不懂)
题意:
给你n盏灯,你有k个质数开关,每个质数开关可以控制是它的倍数的灯,每盏灯被打开奇数次才会亮,问如何控制开关使得亮的灯泡最多
解法:
对于<31的质数开关,直接暴力枚举所有状态,对于>=31的开关(任意两个>=31的质数开关不可能共同控制同一盏灯),就贪心一下,如果把它开起来能激活更多的灯,就开,否则就关。
#include
#include
#include
#include
#include
#include
#include
#include
H题:(博弈dp)
题意:
有两支队,每只队都有n个人,一共有m个蛋糕,每个人至少吃一个,最多吃k个。
都采取最优策略,谁吃到最后一个蛋糕,那么那只队就胜利。
按照给定的顺序去吃蛋糕,问你最后谁胜利。
解法:
先缩点,把相同的点都缩成一个点。
那么就变成了ABABABA这样交替的形式了,然后跑DP就好了。
#include
using namespace std;
const long long llINF = 9223372036854775807;
const int INF = 2147483647;
const int maxn = 1e3 + 7;
const double pi = acos(-1.0);
int t, n, m, k;
char s[maxn << 1];
int dp[maxn << 1][maxn << 1];
vector v;
int dfs(int now, int rest)
{
if (dp[now][rest] != -1)
return dp[now][rest];
if (rest <= v[now] * k)
return dp[now][rest] = 1;
dp[now][rest] = 0;
for (int i = v[now]; i <= k * v[now]; i++)
if (dfs(now + 1, rest - i) == 0)
return dp[now][rest] = 1;
return dp[now][rest];
}
int main(int argc, char const *argv[])
{
scanf("%d", &t);
for (int kase = 1; kase <= t; kase++)
{
scanf("%d%d%d", &n, &m, &k);
n *= 2;
memset(dp, -1, sizeof(dp));
v.clear();
scanf("%s", s + 1);
for (int i = 1; i <= n; i++)
{
int j = i + 1;
while (j <= n && s[j] == s[i])
j++;
v.push_back(j - i); //每次的人数
i = j - 1;
}
printf("Case #%d: ", kase);
if (dfs(0, m))
puts(s[1] == 'A' ? "A" : "B");
else
puts(s[1] == 'A' ? "B" : "A");
}
return 0;
}