• AtCoder Beginner Contest 220


    AtCoder Beginner Contest 220

    D - FG operation

    题目

    (n)个数,每次可以进行两种操作:

    1. 取出前两个数,相加后对(10)取模并将结果放入数列最左端
    2. 取出前两个数,相乘后对(10)取模并将结果放入数列最左端

    问,有多少种方案,使得最终结果等于(k),(k)取0到9的整数.

    思路

    明显的DP,设(f_{i,j})表示消除前(i)个数后最前端的数为(j)的方案数.

    (f_{i+1,jcdot a_i \%10}=f_{i+1,jcdot a_i \%10}+f_{i,j})

    (f_{i+1,(j+a_i)\%10}=f_{i+1,(j+a_i)\%10}+f_{i,j})

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <string>
    #define int long long
    using namespace std;
    int read() {
    	int re = 0;
    	char c = getchar();
    	bool negt = false;
    	while(c < '0' || c > '9')
    		negt |= (c == '-') , c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    	return negt ? -re : re;
    }
    
    const int mod = 998244353;
    const int N = 100010;
    int n , a[N];
    int f[N][12];
    signed main() {
    	n = read();
    	for(int i = 1 ; i <= n ; i++)
    		a[i] = read();
    	
    	++f[2][(a[1] + a[2]) % 10];
    	++f[2][(a[1] * a[2]) % 10];
    	for(int i = 2 ; i < n ; i++)
    		for(int j = 0 ; j < 10 ; j++) {
    			f[i + 1][(j + a[i + 1]) % 10] += f[i][j] , f[i + 1][(j + a[i + 1]) % 10] %= mod;
    			f[i + 1][(j * a[i + 1]) % 10] += f[i][j] , f[i + 1][(j * a[i + 1]) % 10] %= mod;
    			
    		}
    	for(int i = 0 ; i < 10 ; i++)
    		cout << f[n][i] << endl;
    	return 0;
    }
    

    E - Distance on Large Perfect Binary Tree

    题目

    思路

    应该是前六题中最难的一道题.

    看下数据范围,大概是(O(n))的.

    所以,我们可以一层一层算,设第(i)层的一个点对答案的贡献为(f(i))则答案就是(sum^n_{i=1}f(i)cdot 2^{i-1}).

    问题就是计算(f(i)).

    分三种情况:直接向下,直接向上,先向上后向下.

    对于第一种情况,如果(i)到二叉树底的距离足够大,产生的贡献就是(2^{d}),否则没有贡献(可以到达以绿框二叉树的任意一个叶子).

    对于第二种情况,如果(i)的深度足够大,产生的贡献就是(1),否则没有贡献.

    //预处理2的次方.
    	p[0] = 1;
    	for(int i = 1 ; i <= n ; i++)
    		p[i] = (p[i - 1] << 1) % mod;
    //在for循环中.
    		if(n - i >= d)
    			tmp += p[d];
    		if(i > d)
    			++tmp;
    

    对于第三种情况:

    如果到树底的距离足够大,我们可以向上一步然后向下,贡献就是(2^{h-1}=2^{d-2}).

    如果深度足够大,贡献就是(2^{h-1}=1).

    除外,我们还可以向上走(2)步,(3)(cdots)再向下走.

    贡献就是(sum^{d-2}_{i=0}2^i).

    那如果距离不够大呢?

    对于右图,容易得到,(d - i < 0)时,深度足够,否则,绿框二叉树的深度最小值为(d - i+1),贡献是(2^{d-i}).

    对于左图,我们设向上走到(j)深度再向下走可以满足条件,则有((i-j)+(n-j)ge d),即(jle frac{i+n-d}2),(j)的最大值就是(lfloor frac{i+n-d}2 floor),绿框二叉树的深度也就是(d-(i-j)).

    所以我们定义一个(l,r).

    		int l = (d - i < 0 ? 0 : d - i);
    		int r = (n - i >= d - 2 ? d - 2 : d - (i - (i + n - d) / 2)) - 1;
    

    答案就是(sum^{r}_{i=1}2^i).根据等比数列,答案就是

    [2^{r+1}-2^l ]

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <string>
    #define int long long
    using namespace std;
    int read() {
    	int re = 0;
    	char c = getchar();
    	bool negt = false;
    	while(c < '0' || c > '9')
    		negt |= (c == '-') , c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    	return negt ? -re : re;
    }
    
    const int mod = 998244353;
    int p[1000010];
    int n , d;
    signed main() {
    	n = read() , d = read();
    	
    	p[0] = 1;
    	for(int i = 1 ; i <= n ; i++)
    		p[i] = (p[i - 1] << 1) % mod;
    	
    	int ans = 0;
    	for(int i = 1 ; i <= n ; i++) {
    		int tmp = 0;
    		if(n - i >= d)
    			tmp += p[d];
    		if(i > d)
    			++tmp;
    		int l = (d - i < 0 ? 0 : d - i);
    		int r = (n - i >= d - 2 ? d - 2 : d - 1 - (i - (i + n - d) / 2));
    		if(l <= r) {
    			tmp += (p[r + 1] - p[l] + mod) % mod;
    		}
    		tmp %= mod;
    		ans = (ans + tmp * p[i - 1]) % mod;
    		
    //		printf("%lld:	%lld
    " , i , tmp);
    	}
    	cout << ans % mod;
    	return 0;
    }
    

    F - Distance Sums 2

    题目

    思路

    简单的树形DP,设(f_i)表示其他点到(i)点的距离之和.

    则有:

    [f_i=f_j-size(i)+(n-size(i)) ]

    其中,(j)(i)的父节点,(size(i))表示以(i)为根的子树大小,方程很直观.

    特别地,根节点的(f)是所有节点的深度之和(深度从0开始).

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <string>
    #define int long long
    using namespace std;
    int read() {
    	int re = 0;
    	char c = getchar();
    	bool negt = false;
    	while(c < '0' || c > '9')
    		negt |= (c == '-') , c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    	return negt ? -re : re;
    }
    
    const int N = 200010;
    
    struct EDGE {
    	int to , nxt;
    }ed[N * 2];
    int head[N];
    void addedge(int u , int v) {
    	static int cnt;
    	++cnt;
    	ed[cnt].to = v , ed[cnt].nxt = head[u] , head[u] = cnt;
    }
    
    
    int n;
    int dep[N];
    int siz[N];
    
    int f[N];
    
    void dfs(int x , int fa) {
    	siz[x] = 1;
    	dep[x] = dep[fa] + 1;
    	for(int i = head[x] ; i ; i = ed[i].nxt) {
    		if(ed[i].to != fa)
    			dfs(ed[i].to , x) , siz[x] += siz[ed[i].to];
    	}
    }
    
    
    void dfs2(int x , int fa) {
    	if(x != 1)
    		f[x] = f[fa] + n - siz[x] - siz[x];
    	for(int i = head[x] ; i ; i = ed[i].nxt) {
    		if(ed[i].to != fa)
    			dfs2(ed[i].to , x);
    	}
    }
    signed main() {
    	n = read();
    	for(int i = 1 ; i < n ; i++) {
    		int u = read() , v = read();
    		addedge(u , v) , addedge(v , u);
    	}
    	
    	dep[0] = -1;
    	dfs(1 , 0);
    	for(int i = 1 ; i <= n ; i++)
    		f[1] += dep[i];
    	
    	dfs2(1 , 0);
    	for(int i = 1 ; i <= n ; i++) {
    		printf("%lld
    " , f[i]);
    	}
    	return 0;
    }
    
    

    G - Isosceles Trapezium

    题目

    ![image-20210928214139088]([ABC220]AtCoder Beginner Contest 220.assets/image-20210928214139088.png)

    思路

    四个点能构成等腰梯形,当且仅当两点的中垂线与另外两点的中垂线重合,且中点不重合.

    然后大水题,STL乱搞.

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int read() {
    	int re = 0;
    	char c = getchar();
    	bool negt = false;
    	while(c < '0' || c > '9')
    		negt |= (c == '-') , c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    	return negt ? -re : re;
    }
    const int N = 1010;
    typedef long long ll;
    typedef pair<pair<ll , ll> , ll> line;
    typedef pair<ll , ll> point;
    line makeline(ll A , ll B , ll C) {
    	return make_pair(make_pair(A , B) , C);
    }
    ll gcd(ll a , ll b) {
    	return b == 0 ? a : gcd(b , a % b);
    }
    
    int n;
    ll x[N] , y[N];
    ll w[N];
    
    #define index index_
    map <line , int> index;
    map <point , ll> a[N * N];
    int cnt;
    int main() {
    	n = read();
    	for(int i = 1 ; i <= n ; i++)
    		x[i] = read() * 2 , y[i] = read() * 2 , w[i] = read();
    	for(int i = 1 ; i <= n ; i++)
    		for(int j = i + 1 ; j <= n ; j++) {
    			point mid;
    			mid.first = (x[i] + x[j]) / 2 , mid.second = (y[i] + y[j]) / 2;
    			ll A , B , C;//直线一般式方程,防止恶心的浮点数(精度问题很麻烦),也防止斜率不存在的尴尬情况.
    			ll delx = x[i] - x[j];
    			ll dely = y[i] - y[j];
    			ll sumw = w[i] + w[j];
    			if(delx == 0)
    				A = 0 , B = 1 , C = -(y[i] + y[j]) / 2;
    			else if(dely == 0)
    				A = 1 , B = 0 , C = -(x[i] + x[j]) / 2;
    			else {
    				A = delx , B = dely , C = -dely * mid.second - delx * mid.first;
    				ll g = (C == 0 ? gcd(A , B) : gcd(gcd(A , B) , C));//化简,保证重合的直线写出来的方程一致
    				A /= g , B /= g , C /= g;
    				if(A < 0)
    					A = -A , B = -B , C = -C;
    			}
    			line l = makeline(A , B , C);
    //			printf("%lld	%lld	%lld:	%lld
    " , A , B , C , sumw);
    			int id;
    			if(index.find(l) == index.end())
    				index[l] = id = ++cnt;
    			else
    				id = index[l];
    			
    			if(a[id].find(mid) == a[id].end())
    				a[id][mid] = sumw;
    			else
    				a[id][mid] = max(a[id][mid] , sumw);
    		}
    	
    	ll ans = -1;
    	for(int i = 1 ; i <= cnt ; i++) {
    		ll max1 = -1 , max2 = -1;
    		for(auto j = a[i].begin() ; j != a[i].end() ; j++) {
    			ll val = j->second;
    			if(val > max1)
    				max2 = max1 , max1 = val;
    			else if(val > max2)
    				max2 = val;
    		}
    		if(max1 != -1 && max2 != -1 && ans < max1 + max2)
    			ans = max1 + max2;
    	}
    	cout << ans;
    	return 0;
    }
    
  • 相关阅读:
    如何配置MySQL
    软件工程第三次作业
    软件工程第二次作业
    软件工程第一次作业
    Python 【面试总结】
    Vue【你知道吗?】
    Python 【面试强化宝典】
    Python 【基础面试题】
    Vue 【前端面试题】
    Redis 【常识与进阶】
  • 原文地址:https://www.cnblogs.com/dream1024/p/15350288.html
Copyright © 2020-2023  润新知