1. 程式人生 > >Atcoder Grand Contest 003 題解

Atcoder Grand Contest 003 題解

位置 發現 clu cpp 模擬 gii icu define -a

A - Wanna go back home

如果有S就必須要有N,反之亦然,如果有E必須要有W,反之亦然。判斷一下就好了。

//waz
#include <bits/stdc++.h>

using namespace std;

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((int)((x).size()))

typedef pair<int, int> PII;
typedef vector<int> VI;
typedef long long int64;
typedef unsigned int uint;
typedef unsigned long long uint64;

#define gi(x) ((x) = F())
#define gii(x, y) (gi(x), gi(y))
#define giii(x, y, z) (gii(x, y), gi(z))

int F()
{
	char ch;
	int x, a;
	while (ch = getchar(), (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘);
	if (ch == ‘-‘) ch = getchar(), a = -1;
	else a = 1;
	x = ch - ‘0‘;
	while (ch = getchar(), ch >= ‘0‘ && ch <= ‘9‘)
		x = (x << 1) + (x << 3) + ch - ‘0‘;
	return a * x;
}

int n;
char str[2333];
bool t[4];

int main()
{
	scanf("%s", str + 1); n = strlen(str + 1);
	for (int i = 1; i <= n; ++i)
	{
		if (str[i] == ‘W‘) t[0] = 1;
		if (str[i] == ‘E‘) t[1] = 1;
		if (str[i] == ‘N‘) t[2] = 1;
		if (str[i] == ‘S‘) t[3] = 1;
	}
	puts(t[0] == t[1] && t[2] == t[3] ? "Yes" : "No");
}

  

B - Simplified mahjong

先O(n)掃一遍,把奇數的能刪就刪去一個。最後每個除以二再求和就好了。

//waz
#include <bits/stdc++.h>

using namespace std;

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((int)((x).size()))

typedef pair<int, int> PII;
typedef vector<int> VI;
typedef long long int64;
typedef unsigned int uint;
typedef unsigned long long uint64;

#define gi(x) ((x) = F())
#define gii(x, y) (gi(x), gi(y))
#define giii(x, y, z) (gii(x, y), gi(z))

int F()
{
	char ch;
	int x, a;
	while (ch = getchar(), (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘);
	if (ch == ‘-‘) ch = getchar(), a = -1;
	else a = 1;
	x = ch - ‘0‘;
	while (ch = getchar(), ch >= ‘0‘ && ch <= ‘9‘)
		x = (x << 1) + (x << 3) + ch - ‘0‘;
	return a * x;
}

int n, a[100010];

long long ans;

int main()
{
	gi(n);
	for (int i = 1; i <= n; ++i) gi(a[i]);
	for (int i = 1; i <= n; ++i)
	{
		if (a[i] & 1)
		{
			if (a[i + 1]) ++ans, --a[i], --a[i + 1];
		}
	}
	for (int i = 1; i <= n; ++i)
	{
		ans += a[i] >> 1;
	}
	printf("%lld\n", ans);
	return 0;
}

  

C - BBuBBBlesort!

我們發現操作2使得奇數偶數獨立,我們只要算應該在奇數位置最後到偶數位置的數有多少個就好了。

//waz
#include <bits/stdc++.h>

using namespace std;

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((int)((x).size()))

typedef pair<int, int> PII;
typedef vector<int> VI;
typedef long long int64;
typedef unsigned int uint;
typedef unsigned long long uint64;

#define gi(x) ((x) = F())
#define gii(x, y) (gi(x), gi(y))
#define giii(x, y, z) (gii(x, y), gi(z))

int F()
{
	char ch;
	int x, a;
	while (ch = getchar(), (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘);
	if (ch == ‘-‘) ch = getchar(), a = -1;
	else a = 1;
	x = ch - ‘0‘;
	while (ch = getchar(), ch >= ‘0‘ && ch <= ‘9‘)
		x = (x << 1) + (x << 3) + ch - ‘0‘;
	return a * x;
}

int n;

PII a[100010];

int main()
{
	gi(n);
	for (int i = 1; i <= n; ++i) gi(a[i].fi), a[i].se = i;
	sort(a + 1, a + n + 1);
	int ans = 0;
	for (int i = 1; i <= n; ++i) if ((a[i].se & 1) != (i & 1)) ++ans;
	printf("%d\n", ans >> 1);
	return 0;
}

  

D - Anticube

首先因子裏有立方的可以直接除掉,不會有影響,那麽一個數對應的就是唯一的,篩法找出那個數字,算一下就好了。

//waz
#include <bits/stdc++.h>

using namespace std;

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((int)((x).size()))

typedef pair<int, int> PII;
typedef vector<int> VI;
typedef long long int64;
typedef unsigned int uint;
typedef unsigned long long uint64;

#define gi(x) ((x) = F())
#define gii(x, y) (gi(x), gi(y))
#define giii(x, y, z) (gii(x, y), gi(z))

int F()
{
	char ch;
	int x, a;
	while (ch = getchar(), (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘);
	if (ch == ‘-‘) ch = getchar(), a = -1;
	else a = 1;
	x = ch - ‘0‘;
	while (ch = getchar(), ch >= ‘0‘ && ch <= ‘9‘)
		x = (x << 1) + (x << 3) + ch - ‘0‘;
	return a * x;
}

int n;

long long s[100010];

map<long long, int> h, t;

int p[3010], fg[3010], pt;

int main()
{
	gi(n);
	for (int i = 1; i <= n; ++i) scanf("%lld", s + i);
	for (int i = 2; i <= 3000; fg[i] ? : p[++pt] = i, ++i)
		for (int j = i << 1; j <= 3000; j += i)
			fg[j] = 1;
	long long mx = 0;
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; 1LL * p[j] * p[j] * p[j] <= s[i]; ++j)
		{
			long long t = 1LL * p[j] * p[j] * p[j];
			while (!(s[i] % t)) s[i] /= t;
		}
		++h[s[i]];
		mx = max(mx, s[i]);
		//cerr << "s = " << s[i] << endl;
	}
	int ans = 0;
	t = h;
	for (auto iter : t)
	{
		long long x = iter.first;
		if (x == 1) continue;
		long long y = 1;
		for (int j = 1; j <= pt; ++j)
		{
			int cnt = 0;
			while (!(x % p[j])) x /= p[j], ++cnt;
			if (cnt == 1) y *= p[j] * p[j];
			else if (cnt == 2) y *= p[j];
		}
		if (x != 1)
		{
			long long s = sqrt(x);
			if (x == s * s)
				y *= s;
			else 
				y *= x * x;
		}
		//cerr << iter.first << ", " << y << ", " << x << endl;
		if(!h.count(y) || iter.first < y) ans += max(iter.second, h.count(y) ? h[y] : 0);
	}
	if (h[1]) ++ans;
	printf("%d\n", ans);
	return 0;
}

  

E - Sequential operations on Sequence

倒著模擬,首先qi變成單調上升的,就可以二分了。

//waz
#include <bits/stdc++.h>

using namespace std;

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((int)((x).size()))

typedef pair<int, int> PII;
typedef vector<int> VI;
typedef long long int64;
typedef unsigned int uint;
typedef unsigned long long uint64;

#define gi(x) ((x) = F())
#define gii(x, y) (gi(x), gi(y))
#define giii(x, y, z) (gii(x, y), gi(z))

int F()
{
	char ch;
	int x, a;
	while (ch = getchar(), (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘);
	if (ch == ‘-‘) ch = getchar(), a = -1;
	else a = 1;
	x = ch - ‘0‘;
	while (ch = getchar(), ch >= ‘0‘ && ch <= ‘9‘)
		x = (x << 1) + (x << 3) + ch - ‘0‘;
	return a * x;
}

const int N = 1e5 + 10;

int n, Q, m;

long long q[N], t[N], s[N];

int find(long long k, int n)
{
	int t = 0;
	for (int i = 19; ~i; --i)
	{
		if (t + (1 << i) > n) continue;
		if (q[t + (1 << i)] <= k) t += 1 << i;
	}
	return t;
}

int main()
{
	gii(n, Q);
	q[++m] = n;
	for (int i = 1; i <= Q; ++i)
	{
		long long x;
		scanf("%lld", &x);
		while (x <= q[m]) --m;
		q[++m] = x;
	}
	t[m] = 1;
	for (int i = m; i; --i)
	{
		long long k = q[i];
		int p = find(k, i - 1);
		while (p)
		{
			t[p] += (k / q[p]) * t[i];
			k %= q[p];
			p = find(k, p - 1);
		}
		s[1] += t[i], s[k + 1] -= t[i];
	}
	long long ans = 0;
	for (int i = 1; i <= n; ++i) ans += s[i], printf("%lld\n", ans);
	return 0;
}

  

F - Fraction of Fractal

首先考慮行有連接列也有連接的,那麽連通塊個數肯定為1,都沒有連接就是黑格子個數的K-1次方,只有一邊連接,假設是行,從K拓展到K+1的時候,公式:K+1層的連通塊個數=K層的黑格子個數-K層的左右格子對,因為上下不會擴展,所以只要減去左右,那麽我們就要維護黑格子個數和左右相連的格子有多少個,還要再維護邊界有多少相鄰,才能轉移。

x‘ = x^2(黑格子個數)

y‘ = z * y + x * y(左右相連格子個數)

z‘ = z * z(邊界相鄰格子數)

矩陣乘法計算就好了。

//waz
#include <bits/stdc++.h>

using namespace std;

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((int)((x).size()))

typedef pair<int, int> PII;
typedef vector<int> VI;
typedef long long int64;
typedef unsigned int uint;
typedef unsigned long long uint64;

#define gi(x) ((x) = F())
#define gii(x, y) (gi(x), gi(y))
#define giii(x, y, z) (gii(x, y), gi(z))

int F()
{
	char ch;
	int x, a;
	while (ch = getchar(), (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘);
	if (ch == ‘-‘) ch = getchar(), a = -1;
	else a = 1;
	x = ch - ‘0‘;
	while (ch = getchar(), ch >= ‘0‘ && ch <= ‘9‘)
		x = (x << 1) + (x << 3) + ch - ‘0‘;
	return a * x;
}

const int mod = 1e9 + 7;

struct matrix
{
	int a[2][2];
	matrix operator * (matrix that) 
	{
		matrix ans;
		memset(ans.a, 0, sizeof ans.a);
		for (int i = 0; i < 2; ++i)
			for (int j = 0; j < 2; ++j)
				for (int k = 0; k < 2; ++k)
					ans.a[i][j] = (ans.a[i][j] + 1LL * a[i][k] * that.a[k][j]) % mod;
		return ans;
	}
} w;

int fpow(int a, long long x)
{
	int ret = 1;
	for (; x; x >>= 1)
	{
		if (x & 1) ret = 1LL * ret * a % mod;
		a = 1LL * a * a % mod;
	}
	return ret;
}

matrix fpow(matrix a, long long x)
{
	matrix ret;
	memset(ret.a, 0, sizeof ret.a);
	ret.a[0][0] = ret.a[1][1] = 1;
	for (; x; x >>= 1)
	{
		if (x & 1) ret = ret * a;
		a = a * a;
	}
	return ret;
}

int H, W;

long long K;

char str[1010][1010];

int main()
{
	scanf("%d%d%lld", &H, &W, &K);
	for (int i = 1; i <= H; ++i)
		scanf("%s", str[i] + 1);
	int cntH = 0, cntW = 0;
	for (int i = 1; i <= H; ++i)
		if (str[i][1] == str[i][W] && str[i][1] == ‘#‘) ++cntH;
	for (int i = 1; i <= W; ++i)
		if (str[1][i] == str[H][i] && str[1][i] == ‘#‘) ++cntW;
	int cnt = 0;
	for (int i = 1; i <= H; ++i)
		for (int j = 1; j <= W; ++j)
			if (str[i][j] == ‘#‘) ++cnt;
	if (!cntH && !cntW)
	{
		printf("%d\n", fpow(cnt, K - 1));
		return 0;
	}
	if ((cntH && cntW) || !K)
	{
		puts("1");
		return 0;
	}
	if (cntH)
	{
		w.a[0][0] = cnt;
		for (int i = 1; i <= H; ++i)
			for (int j = 1; j < W; ++j)
				if (str[i][j] == ‘#‘ && str[i][j + 1] == ‘#‘)
					++w.a[0][1];
		w.a[1][1] = cntH;
	}
	else
	{
		w.a[0][0] = cnt;
		for (int i = 1; i < H; ++i)
			for (int j = 1; j <= W; ++j)
				if (str[i][j] == ‘#‘ && str[i + 1][j] == ‘#‘)
					++w.a[0][1];
		w.a[1][1] = cntW;
	}
	w = fpow(w, K - 1);
	printf("%d\n", (w.a[0][0] - w.a[0][1] + mod) % mod);
	return 0;
}

  

Atcoder Grand Contest 003 題解