• AtCoder Beginner Contest 209 题解


    本场链接:AtCoder Beginner Contest 209

    C - Not Equal

    不难注意到:(A_i)的次序无关,因为每个元素都不同,只需要考虑每个元素在他的区间内的取值即可.因此按上升对(C_i)排序,由于整个数组成上升,所以当做到(C_i)的时候,上限相当于去掉了(i - 1)个元素,如此即可统计答案.

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    
    const int N = 2e5+7,MOD = 1e9 + 7;
    int c[N];
    
    int main()
    {
        int n;scanf("%d",&n);
        forn(i,1,n) scanf("%d",&c[i]);
        sort(c + 1,c + n + 1);
    
        int res = 1;
        forn(i,1,n) res = 1ll * res * max(0,c[i] - i + 1) % MOD;
        printf("%d
    ",res);
        return 0;
    }
    
    

    D - Collision

    弱智题,两个点会走到一个点是距离为偶数,反之是奇数.求树上任意两点距离即可.

    #define _CRT_SECURE_NO_WARNINGS
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+7,M = 4e5+7,LIM = 17;
    int edge[M],succ[M],cost[M],ver[N],idx;
    int n,m,hh,tt,q[M];
    int depth[N],fa[N][LIM + 3],dist[N];
    void add(int u,int v,int w)
    {
    	edge[idx] = v;
    	cost[idx] = w;
    	succ[idx] = ver[u];
    	ver[u] = idx++;
    }
    void bfs()
    {
    	memset(depth,0x3f,sizeof depth);
    	memset(dist,0x3f,sizeof dist);
    	depth[1] = 0;depth[0] = -1;q[++tt] = 1;dist[1] = 0;
    	while(hh <= tt)
    	{
    		int u = q[hh++];
    		for(int i = ver[u];~i;i = succ[i])
    		{
    			int v = edge[i];
    			if(depth[v] > depth[u] + 1)
    			{
    				dist[v] = dist[u] + cost[i];
    				depth[v] = depth[u] + 1;
    				fa[v][0] = u;
    				q[++tt] = v;
    				for(int k = 1;k <= LIM;++k)
    					fa[v][k] = fa[fa[v][k - 1]][k - 1];
    			}
    		}
    	}
    }
    int lca(int x,int y)
    {
    	if(depth[x] < depth[y])	swap(x,y);
    	for(int i = LIM;i >= 0;--i)
    		if(depth[fa[x][i]] >= depth[y])
    			x = fa[x][i];
    	if(x == y)	return x;
    	for(int i = LIM;i >= 0;--i)
    		if(fa[x][i] != fa[y][i])
    			x = fa[x][i],y = fa[y][i];
    	return fa[x][0];
    }
    int main()
    {
    	memset(ver,-1,sizeof ver);
    	scanf("%d%d",&n,&m);
    	for(int i = 1;i < n;++i)
    	{
    		int u,v;scanf("%d%d",&u,&v);
    		add(u,v,1);add(v,u,1);
    	}
    	bfs();
    	while(m--)
    	{
    		int u,v;scanf("%d%d",&u,&v);
    		if((dist[u] + dist[v] - 2 * dist[lca(u,v)]) % 2 == 0)   puts("Town");
    		else puts("Road");
    	}
        return 0;
    }
    
    

    E - Shiritori

    首先优化建图:如果直接建图整个图的边数会达到(N^2)无法承受.将所有首尾三个元素相同的元素合并到一个点,边由每个(s_i)决定:首对应的点是(u)尾对应的点是(v)则建(u->v)的边.

    考虑求答案:如果这张图上没有环显然是可以直接递推的:在反图上跑拓扑排序即可.但是有环其实也不影响,最终所有没有确定状态的点都是平局.

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    #define x first
    #define y second
    
    const int N = 52 * 52 * 52 + 7,M = 2 * N,C = 2e5+7;
    char s[10];
    vector<pii> edges(C);
    vector<int> E[N];
    int deg[N],ans[N];
    
    inline int gpos(char a)
    {
        if(a >= 'A' && a <= 'Z')    return a - 'A';
        return a - 'a' + 26;
    }
    inline int gid(char a,char b,char c)
    {
        return gpos(a) * 52 * 52 + gpos(b) * 52 + gpos(c);
    }
    
    int main()
    {
        int n;scanf("%d",&n);
        forn(i,1,n)
        {
            scanf("%s",s + 1);int len = strlen(s + 1);
            edges[i] = {gid(s[1],s[2],s[3]),gid(s[len - 2],s[len - 1],s[len])};
            ++deg[edges[i].x];
            E[edges[i].y].push_back(edges[i].x);
        }
    
        queue<int> q;memset(ans,-1,sizeof ans);
        forn(i,0,N - 1) if(!deg[i]) q.push(i),ans[i] = 0;
        while(!q.empty())
        {
            int u = q.front();q.pop();
            for(auto& v : E[u])
            {
                if(ans[v] != -1)    continue;
                --deg[v];
                if(ans[u] == 0) ans[v] = 1,q.push(v);
                else if(!deg[v])    ans[v] = 0,q.push(v);
            }
        }
        forn(i,1,n)
        {
            if(ans[edges[i].y] == -1)   puts("Draw");
            else if(ans[edges[i].y] == 0)   puts("Takahashi");
            else puts("Aoki");
        }
        return 0;
    }
    
    

    F - Deforestation

    这个题如果只是要求最小值,是一个出烂的玩意,但是要求方案数,手玩一下发现原来求最小值的贪心对于求方案数没有任何贡献.

    考虑从题目本身做:对于每个(H_i)对于答案的贡献是多少?当删去(H_i)的时候一定会产生(H_i)的贡献,当删去(H_{i+1})的时候,(H_i)会产生贡献当且仅当(H_{i+1})是先于(H_i)被砍的.同理当删去(H_{i-1})的时候,(H_i)会产生贡献当且仅当(H_{i-1})先于(H_i)被删掉.

    从前往后考虑每个元素(i in [1,n-1]):

    • (H_i < H_{i+1}),那么(H_i)的删去时间应该晚于(H_{i+1}),否则会让(H_{i+1})往答案贡献两次而不是(H_i)贡献两次(显然后者更优).
    • (H_i > H_{i+1}),那么(H_i)的删去时间应该早于(H_{i+1}),原因同上.
    • 若两者相同,显然先后不会再对贡献有影响.

    如此可以考虑一个dp:

    • 状态:(f[i][j])表示分配前(i)个元素,末尾元素被安排在(j)位置上的方案数.
    • 入口:(f[1][1] = 1)其他为(0).
    • 转移:对于(i in[2,n]),若(H_i == H_{i-1})(f[i][j] = sumlimits_{k = 1}^i f[i - 1][k]),若(H_i < H_{i-1}),则(f[i][j] = sumlimits_{k = j}^i f[i - 1][k]),若(H_i > H_{i-1}),则(f[i][j] = sumlimits_{k = 1}^{j - 1} f[i - 1][k]).当(j == k)时,认为是(H_i)插入到(H_{i-1})的前面.
    • 出口:(ans = sumlimits_{k = 1}^n f[n][i]).

    转移部分,在每次处理完(i)维的转移后,记录本维状态的前缀和,即可将转移复杂度降到可以承受的(O(n^2)).

    注意给(sum[1] = 1)初值.

    ($j == k的情况如何处理有些怪,以后补)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    
    const int N = 4005,MOD = 1e9+7;
    int H[N],f[N][N],sum[N];
    
    int main()
    {
        int n;scanf("%d",&n);
        forn(i,1,n) scanf("%d",&H[i]);
    
        f[1][1] = sum[1] = 1;
        forn(i,2,n)
        {
            forn(j,1,i)
            {
                if(H[i] == H[i - 1])    f[i][j] = sum[i - 1];
                else if(H[i] < H[i - 1])    f[i][j] = ((sum[i - 1] - sum[j - 1]) % MOD + MOD) % MOD;
                else f[i][j] = sum[j - 1];
            }
            forn(j,1,n) sum[j] = (f[i][j] + sum[j - 1]) % MOD;
        }
        
        int res = 0;
        forn(i,1,n) res = (res + f[n][i]) % MOD;
        printf("%d
    ",res);
        return 0;
    }
    
    
  • 相关阅读:
    GAIN: Gradient Augmented Inpainting Network for Irregular Holes
    Python+Selenium实现对浏览器的自动操作
    python 中的内置类属性__name__和__doc__
    Python 装饰器
    Free-Form Image Inpainting with Gated Convolution
    解决ubuntu安装软件has install-snap change in progress错误
    Image Inpainting for Irregular Holes Using Partial Convolutions
    理解卷积
    Hive中分区表修复问题
    B2B、B2C、C2C、O2O分别是什么意思?
  • 原文地址:https://www.cnblogs.com/HotPants/p/15003527.html
Copyright © 2020-2023  润新知