8.13总结当日

今天我们队排名第四,然后总排排第6,勉强站住了区域赛的位置,还有12天,要继续加油啊


8.13场地址


B题:(Tarjan||暴力)

题意:

有一幅图,然后问你这幅图里面有多少个子图满足图的两个部分是完全对称的,而且这两个图要是完全图

解法:

由于\large N*M最大为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个数字,\large n_{i} 表示第i个元素的父亲节点为\large 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef long long ll;
using namespace std;
typedef unsigned long long int ull;
#define maxn 200005
#define ms(x) memset(x,0,sizeof(x))
#define Inf 0x7fffffff
#define inf 0x3f3f3f3f
const int mod = 1e9 + 7;
#define pi acos(-1.0)
#define pii pair
#define eps 1e-5
#define pll pair
#define lson 2*x
#define rson 2*x+1

int vis[maxn];
int t, n, k;

void Find(int &res, int x) {
	int i, j;
	for (i = x; i <= n; i += x) {
		if (vis[i] == 1)vis[i] = 0;
		else vis[i] = 1;
		if (vis[i])res++;
		else res--;
	}
}

int main() {
	scanf("%d", &t);
	int cnt = 0;

	while (t--) {
		cnt++;
		int i, j;
		vectorve1, ve2;
		scanf("%d%d", &n, &k);

		for (i = 1; i <= k; i++) {
			int c; c = read();
			if (c < 29)ve1.push_back(c);
			else ve2.push_back(c);
		}

		int maxx = 0;
		for (i = 0; i < (1 << ve1.size()); i++) {
			int res = 0;
			ms(vis);

			for (j = 0; j < ve1.size(); j++) {
				if ((1 << j)&i) {
					Find(res, ve1[j]);
				}
			}

			for (j = 0; j < ve2.size(); j++) {
				int tmp = 0;
				Find(tmp, ve2[j]);
				res += max(0, tmp);
			}

			maxx = max(maxx, res);
		}
		//cout << maxx  << endl;
		printf("Case #%d: %d\n", cnt, maxx);
	}
}

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;
}

 

你可能感兴趣的:(2018暑假ACM集训)