zoukankan      html  css  js  c++  java
  • Atcoder Grand Contest 001 题解

    最近在刷AGC,就写一下题解。

    A - BBQ Easy

    sort完,每相邻两个组成一组,发现这样肯定是最优的。

    //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, L[210], ans;
     
    int main()
    {
    	gi(n);
    	for (int i = 1; i <= (n << 1); ++i) gi(L[i]);
    	sort(L + 1, L + 2 * n + 1);
    	for (int i = 1; i <= (n << 1); i += 2) ans += L[i];
    	printf("%d
    ", ans);
    	return 0;
    }
    

      

    B - Mysterious Light

    把光线分成很多平行四边形,所有平行四边形做法一样,只要递归下去就好了,只要某一边是另一边倍数就到达终点了,所以复杂度和gcd一样,是log的。

    //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;
    }
     
    long long ans = 0;
     
    void work(long long x, long long y)
    {
    	if (x < y)
    	{
    		ans += (y / x) * x * 2 - x;
    		if (y % x == 0)
    			return;
    		ans += x;
    		work(x, y % x);
    	}
    	else
    	{
    		ans += (x / y) * y * 2 - y;
    		if (x % y == 0)
    			return;
    		ans += y;
    		work(y, x % y);
    	}
    }
     
    int main()
    {
    	long long N, X;
    	cin >> N >> X;
    	ans += N;
    	work(X, N - X);
    	cout << ans << endl;
    }
    

      

    C - Shorten Diameter

    枚举根,如果是偶数,所有深度要小于等于k/2,如果是奇数,则有一个根的儿子里所有点的深度可以最大为k/2+1,其他都为k/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;
    }
     
    const int N = 2010;
     
    VI edge[N];
     
    int n, k, dep[N], mxd;
     
    void dfs(int u, int fa, int d)
    {
    	if (k & 1) if(d > k / 2 + 1) return;
    	if (!(k & 1)) if (d > k / 2) return;
    	++dep[d];
    	mxd = max(mxd, d);
    	for (auto v : edge[u])
    		if (v != fa)
    		{
    			dfs(v, u, d + 1);
    		}
    }
     
    int main()
    {
    	gii(n, k);
    	for (int i = 1; i < n; ++i)
    	{
    		int u, v;
    		gii(u, v);
    		edge[u].pb(v);
    		edge[v].pb(u);
    	}
    	int res = 0;
    	for (int root = 1; root <= n; ++root)
    	{
    		int mx = 0, s = 1;
    		for (auto son : edge[root])
    		{
    			mxd = 0;
    			dfs(son, root, 1);
    			if (k & 1) mx = max(mx, dep[k / 2 + 1]);
    			if (k & 1) s -= dep[k / 2 + 1];
    			for (int i = 1; i <= mxd; ++i) s += dep[i], dep[i] = 0;
    		}
    		res = max(res, s + mx);
    	}
    	printf("%d
    ", n - res);
    	return 0;
    }
    

      

    D - Arrays and Palindrome

    有一个结论:奇数不能超过2,否则无解,有解的话就把奇数放在两端,然后每次错1位放b就能保证他们全部相等了。

    //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, m, a[110];
     
    bool comp(const int &i, const int &j)
    {
    	return (i & 1) > (j & 1);
    }
     
    int b[110], ans;
     
    int main()
    {
    	gii(n, m);
    	int cnt = 0;
    	for (int i = 1; i <= m; ++i) gi(a[i]);
    	for (int i = 1; i <= m; ++i)
    		if (a[i] & 1) ++cnt;
    	if (cnt > 2)
    	{
    		puts("Impossible");
    		return 0;
    	} 
    	sort(a + 1, a + m + 1, comp);
    	if (a[2] & 1) swap(a[2], a[m]);
    	for (int i = 1; i <= m; ++i)
    		printf("%d ", a[i]);
    	puts("");
    	if (m == 1)
    	{
    		if (a[1] - 1) printf("2
    %d %d 
    ", 1, a[1] - 1);
    		else printf("1
    %d 
    ", 1);
    		return 0;
    	}
    	if (a[1] - 1) b[++ans] = a[1] - 1;
    	for (int i = 2; i < m; ++i)
    		b[++ans] = a[i];
    	b[++ans] = a[m] + 1;
    	printf("%d
    ", ans);
    	for (int i = 1; i <= ans; ++i)
    		printf("%d ", b[i]);
    	puts("");
    	return 0;
    }
    

      

    E - BBQ Hard

    首先答案是sigma(i<j) C(a[i]+a[j]+b[i]+b[j],a[i]+a[j]),一个C(a[i]+a[j]+b[i]+b[j],a[i]+a[j])可以看作从(-a[i],-b[i])走到(a[j],b[j])的方案数,所以我们所有dp一次性做了,减去一个点自己到自己,最后除以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;
    }
     
    const int mod = 1e9 + 7;
     
    int n;
     
    int dp[4010][4010];
     
    PII x[200010];
     
    int& f(int x, int y) { return dp[x + 2005][y + 2005]; }
     
    int inc(int x, int y)
    {
    	x += y;
    	if (x >= mod) x -= mod;
    	return x;
    }
     
    int dec(int x, int y)
    {
    	x -= y;
    	if (x < 0) x += mod;
    	return x;
    }
     
    int fpow(int a, int x)
    {
    	int ret = 1;
    	for (; x; x >>= 1)
    	{
    		if (x & 1) ret = 1LL * ret * a % mod;
    		a = 1LL * a * a % mod;
    	}
    	return ret;
    } 
     
    int fac[8010], ifac[8010];
     
    int C(int n, int m)
    {
    	if (n < m || m < 0) return 0;
    	return 1LL * fac[n] * ifac[m] % mod * ifac[n - m] % mod;
    }
     
    int main()
    {
    	fac[0] = 1;
    	for (int i = 1; i <= 8000; ++i)
    		fac[i] = 1LL * fac[i - 1] * i % mod;
    	ifac[8000] = fpow(fac[8000], mod - 2);
    	for (int i = 8000; i; --i)
    		ifac[i - 1] = 1LL * ifac[i] * i % mod;
    	gi(n);
    	for (int i = 1; i <= n; ++i)
    		gii(x[i].fi, x[i].se), ++f(-x[i].fi, -x[i].se);
    	for (int i = -2000; i <= 2000; ++i)
    		for (int j = -2000; j <= 2000; ++j)
    			f(i, j) = inc(f(i, j), f(i - 1, j)), f(i, j) = inc(f(i, j), f(i, j - 1));
    	int ans = 0;
    	for (int i = 1; i <= n; ++i)
    		ans = inc(ans, f(x[i].fi, x[i].se));
    	for (int i = 1; i <= n; ++i)
    		ans = dec(ans, C((x[i].fi + x[i].se) << 1, x[i].fi << 1));
    	ans = 1LL * ans * fpow(2, mod - 2) % mod;
    	printf("%d
    ", ans);
    	return 0;
    }
    

      

    F - Wide Swap

    我们可以令q[p[i]]=i,那么就是相邻的如果|q[i]-q[i+1]|>=k就能交换,所以相对顺序不变,也就是|i-j|<k,p[i]<p[j]是固定的。如果i向j连边就是拓扑排序问题,边是n^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;
    }
     
    const int N = 5e5 + 10;
     
    int n, k, p[N], q[N];
     
    int t[N << 2], cnt;
     
    int get(int x, int y)
    {
    	if (!x) return y;
    	if (!y) return x;
    	return min(x, y);
    }
     
    void modify(int x, int v)
    {
    	t[x += cnt] = v;
    	for (x >>= 1; x; x >>= 1)
    		t[x] = get(t[x << 1], t[x << 1 | 1]);
    }
     
    int query(int l, int r)
    {
    	int ans = 0;
    	l = max(l, 1);
    	r = min(r, n);
    	if (l > r) return 0;
    	for (l += cnt - 1, r += cnt + 1; l ^ r ^ 1; l >>= 1, r >>= 1)
    	{
    		if (~l & 1) ans = get(ans, t[l ^ 1]);
    		if ( r & 1) ans = get(ans, t[r ^ 1]);
    	}
    	return ans;
    }
     
    vector<int> edge[N];
     
    int deg[N];
     
    priority_queue<int> pq;
     
    int ans[N];
     
    int main()
    {
    	gii(n, k);
    	for (int i = 1; i <= n; ++i) gi(p[i]), q[p[i]] = i;
    	for (cnt = 1; cnt < n + 2; cnt <<= 1); --cnt;
    	for (int i = n; i; --i)
    	{
    		int x = q[query(q[i] - k + 1, q[i] - 1)];
    		if (x) edge[q[i]].pb(x), ++deg[x];
    		x = q[query(q[i] + 1, q[i] + k - 1)];
    		if (x) edge[q[i]].pb(x), ++deg[x];
    		modify(q[i], i);
    	}
    	for (int i = 1; i <= n; ++i)
    		if (!deg[i]) pq.push(-i);
    	int cur = 0;
    	while (!pq.empty())
    	{
    		int u = -pq.top(); pq.pop();
    		ans[u] = ++cur;
    		for (auto v : edge[u])
    		{
    			--deg[v];
    			if (!deg[v])
    				pq.push(-v);
    		}
    	}
    	for (int i = 1; i <= n; ++i)
    		printf("%d
    ", ans[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    页码pageNo与SQL的limit进行换算
    Linux(centos)使用shell脚本停止启动jar包
    Linux执行脚本报错:-bash: ./xx.sh: /bin/bash^M: bad interpreter: No such file or directory
    Linux启动、停止宝塔
    Linux报错:ERROR>the input device is not a TTY
    mybatis基于注解的sql中空字符串判断
    题解 「CTSC2018暴力写挂」
    题解 Beautiful Pair
    【模板】常系数齐次线性递推
    斐波那契的最小公倍数 题解
  • 原文地址:https://www.cnblogs.com/AnzheWang/p/9606818.html
Copyright © 2011-2022 走看看