AtCoder Grand Contest 009 题解

A - Multiple Array

倒着算要加多少就好了。

//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;
 
long long a[N], b[N];
 
int main()
{
	gi(n);
	for (int i = 1; i <= n; ++i)
		gii(a[i], b[i]);
	long long add = 0;
	for (int i = n; i; --i)
	{
		a[i] += add;
		if (a[i] % b[i]) add += b[i] - a[i] % b[i], a[i] += b[i] - a[i] % b[i];
	}
	printf("%lld\n", add);
	return 0;
}

  

B - Tournament

树形dp,把所有儿子的轮数从小到大排序,算一下自己最少要多少轮即可。

//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];
 
VI edge[100010];
 
int rd[100010];
 
void dfs(int u)
{
	VI p;
	for (auto v : edge[u])
	{
		dfs(v);
		p.pb(rd[v]);
	}
	sort(ALL(p));
	for (auto x : p)
		rd[u] = max(rd[u], x), ++rd[u];
}
 
int main()
{
	gi(n);
	for (int i = 2; i <= n; ++i) gi(a[i]), edge[a[i]].pb(i);
	dfs(1);
	printf("%d\n", rd[1]);
	return 0;
}

  

C - Division into Two

列出dp方程,令A>=B,把可以取的位置丢进树状数组维护一下dp即可。

//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, mod = 1e9 + 7;
 
int n;
 
int64 A, B, S[N];
 
int lf[N], f[N], g[N];
 
int t[N];
 
void add(int x, int v) { for (++x; x <= n + 1; x += x & -x) t[x] = (t[x] + v) % mod; }
 
int query(int x) { int v = 0; for (++x; x; x -= x & -x) v = (v + t[x]) % mod; return v; }
 
int main()
{
	gi(n);
	scanf("%lld%lld", &A, &B);
	if (A < B) swap(A, B);
	for (int i = 1; i <= n; ++i) scanf("%lld", S + i); S[0] = -A;
	++n; S[n] = S[n - 1] + A;
	lf[1] = 1;
	for (int i = 2; i <= n; ++i) if (S[i] >= S[i - 1] + B) lf[i] = lf[i - 1]; else lf[i] = i;
	f[0] = 1;
	add(0, f[0]);
	for (int i = 1; i <= n; ++i)
	{
		int k = upper_bound(S + 1, S + i + 1, S[i] - A) - S - 1;
		int j = lf[i - 1] - 1;
		if (S[i] - S[i - 1] >= A) f[i] = f[i - 1];
		if (i >= 2 && min(i - 2, k) >= j - 1) (f[i] += (query(min(i - 2, k)) - query(j - 1) + mod) % mod) %= mod;
		if (i < n && S[i + 1] - S[i - 1] >= B) add(i, f[i]);
	}
	printf("%d\n", f[n]);
	return 0;
}

  

D - Uninity

树分治是上界,也就是log,当有两个点是第k次标号,中间肯定要有一个k+1,用这个进行dp,算一下每个点的所有儿子令它最大是多少就好了。

//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;
 
VI edge[N];
 
int n, bit[N], f[N];
 
void dfs(int u, int fa)
{
	int l = 0;
	for (auto v : edge[u])
	{
		if (v == fa) continue;
		dfs(v, u);
		l |= bit[u] & bit[v];
		bit[u] |= bit[v];
	}
	if (!bit[u]) bit[u] = 1;
	else
	{
		while ((1 << f[u]) < l || ((1 << f[u]) & bit[u])) ++f[u];
		bit[u] = ((bit[u] >> f[u]) << f[u]) | (1 << f[u]);
	}
	f[0] = max(f[0], f[u]);
}
 
int main()
{
	gi(n);
	for (int i = 1; i < n; ++i)
	{
		int u, v;
		gii(u, v);
		edge[u].pb(v);
		edge[v].pb(u);
	}
	dfs(1, 0);
	printf("%d\n", f[0]);
	return 0;
}

  

E - Eternal Average

转换为k叉树模型,发现最后要求的是一个符合条件序列的个数,dp一下即可。

//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;
 
int n, m, k, ans;
 
int f[2][2010][2], sum[2010];
 
int main()
{
	giii(n, m, k);
	--m, --k;
	for (int i = 1; i <= k; ++i) f[0][i][1] = 1;
	f[0][0][0] = 1;
	for (int i = 0; i <= n; ++i) 
		if (k - i <= m && i % k == n % k && (k - i) % k == m % k) ans = (ans + f[0][i][1]) % mod;
	int now = 0;
	for (int i = 2; i <= max(n, m) * 2; ++i)
	{
		now ^= 1;
		for (int j = 0; j <= n; ++j) sum[j + 1] = (sum[j] + (f[now ^ 1][j][0] + f[now ^ 1][j][1]) % mod) % mod;
		for (int j = 0; j <= n; ++j)
		{
			f[now][j][0] = (sum[j + 1] - sum[j] + mod) % mod;
			f[now][j][1] = (sum[j] - sum[max(0, j - k)] + mod) % mod;
		}
		for (int j = 0; j <= n; ++j)
			if (k * i - j <= m && j % k == n % k && (k * i - j) % k == m % k) ans = (ans + f[now][j][1]) % mod;
		//cerr << ans << endl;
	}
	printf("%d\n", ans);
}

  

posted @ 2018-09-13 17:41  AnzheWang  阅读(210)  评论(0编辑  收藏  举报