zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    OSG-提示“error reading file e:1.jpg file not handled”
    OSG-加载地球文件报0x00000005错误,提示error reading file simple.earth file not handled
    QT-找开工程后,最上方提示the code model could not parse an included file, which might lead to incorrect code completion and highlighting, for example.
    我的书《Unity3D动作游戏开发实战》出版了
    java中无符号类型的第三方库jOOU
    Windows批处理备份mysql数据
    使用 DevTools 时,通用Mapper经常会出现 class x.x.A cannot be cast to x.x.A
    Java版本,Java版本MongoDB驱动,驱动与MongoDB数据库,Spring之间的兼容性
    Jrebel本地激活方法
    wget下载指定网站目录下的所有内容
  • 原文地址:https://www.cnblogs.com/HotPants/p/15003527.html
Copyright © 2011-2022 走看看