• 5.18周赛


    反思一下,A题要不是第三个样例可能就WA不知道多少分了,即使有第三个样例step2 - (x + y)) % 2要等于0我也推了好久(差点没整出来)
    然后一直在B,C之间犹豫,想一会儿C想一会儿B的,结果差点两道题都没有做出来
    B题出了好几个智障错误:
    从1开始A,B一起枚举结果忘了i - A或者i - B可能(其实是一定)会小于0然后出现未知错误,搞了好久分开枚举才过了样例,这么点小事还是考试之后Phenning巨佬告诉我的
    枚举水的时候误以为只要是一次性的背包就都从大到小枚举,忽略了一次性背包问题枚举的本质(不能让一个东西被反复更新)因为/2是一个变小的行为,所以需要从小到大枚举才不会导致同一个被更新了一次又一次
    结果没时间做C了,光荣垫底orz orz orz
    C题即使是在考试之后得知Tarjan也没做出来orz orz orz
    果然还是我太弱了(反思),平时做的题也太少了,过于依赖讲义,评讲什么的,,,,,一到自己做题就完全懵逼了,,,orz orz orz

    A

    显然时间等于走的步数

    观察一下样例2

    发现只用用step2,x2,y2记录一个上一次的步数和坐标,再与这一次的step,x,y比较一下,如果(step - step2) < abs(x2 - x) + abs(y2 - y)就标记一个flag = 1;

    观察样例3

    if((step2 - (x + y)) % 2)也是不行的,也需要标记flag = 1(因为类似于“消磨时间”的走法一定是走偶数步,所以步数与位置的曼哈顿距离必须同奇偶)
    边输入边扫,扫完之后看一下flag,如果等于0就输出Yes,等于1就输出No


    B

    一个最简单的NKOJ上的背包问题1加背包问题2的联合
    A,B分别为无限物品,水为仅能用一次的有限物品

    具体过程
    v[0] = true;
    for(int i = A; i <= T; i ++)if(v[i - A])v[i] = true;
    for(int i = B; i <= T; i ++)if(v[i - B])v[i] = true;
    
    for(int i = 0; i <= T; i ++)if(v[i])v[i / 2] = true;
    //注意一下,由于这里i是除法,也就是越更新越小,所以for循环从小到大枚举i
    //举个栗子:假设f[6] = true,我们将f[3]也标记为true
    
    for(int i = A; i <= T; i ++)if(v[i - A])v[i] = true;
    for(int i = B; i <= T; i ++)if(v[i - B])v[i] = true;
    //再来一遍就可以了orz orz orz
    

    C

    每个人都有一个固定的信息传递对象 —> 每个人的出度都是1
    找最少进行几轮可以转换成最少经过几个人—>找最小环
    因为每个人的出度都是1,所以不会出现环套环的情况,即可以求最小环
    解法:用Tarjan找强连通分量,每一个强连通分量都是一个环,在从栈里面弹出点的时候记录一下每一个强连通分量内点的个数,只要不是1就比较出最小的一个


    D

    一道没有人通过的水题orz(当然我是完全不会的)
    如果只有一种球:逆序对(凡是交换相邻两个的都是求逆序对) —> 两种球:两个逆序对orz
    设白球:1 ~ i个
    黑球:1 ~ j个
    无论怎么排,一定会占满2n个里面前i + j个位置
    所以可以设一个状态f[i][j],表示前i加j个位置中放白球前i个,黑球前j个,所需最少交换次数
    决策:i + j号位置放i号白球还是j号黑球
    方程:f[i][j] = min{f[i - 1][j] + cntWhite[i][j],f[i][j -1] + cntBlack[i][j]}
    cntWhite[i][j] = ① + ②:
    ①[1,i - 1]白球中,位于i右侧的,都要调整到i左侧(逆序对)
    ②[1, j]黑球中,位于i右侧的,都要调整到i左侧(逆序对)
    cntBlack[i][j] = ③ + ④:
    ③[1, i]白球中,位于j右侧的,都要调整到j左侧
    ④[1,j - 1]黑球中,位于j右侧的,都要调整到j左侧
    如何求cnt?——暴力枚举!

    cntW的求法
    for(int i = 0; i <= n; i ++){
        	for(int j = 1; j < i; j ++)
                if(posw[i] < posw[j]) cntW[i][0] ++;
    	
            for(int j = 1; j <= n; j ++){
            	cntW[i][j] = cntW[i][j - 1];
            	if(posw[i] < posb[j]) cntW[i][j] ++;
        	}
        }
    
    cntB的求法
    for(int i = 0; i <= n; i ++){
    	for(int j = 1; j < i; j ++)
    		if(posb[i] < posb[j]) cntB[0][i] ++;
    			
    	for(int j = 1; j <= n; j ++){
    		cntB[j][i] = cntB[j - 1][i];
    		if(posb[i] < posw[j])cntB[j][i] ++;
    	}
    }
    

    一般来说数组是存对应位置是哪个球
    但是这里我们存的是对应编号是哪个位置
    感觉是这辈子自己都想不出来的orz orz orz


    AC代码如下

    A

    #include <stdio.h>
    #include <bits/stdc++.h>
    using namespace std;
    int n, x, y, step1, step2;
    int lastx, lasty;
    bool flag = false;
    int main(){
    	scanf("%d", &n);
    	for(int i = 1; i <= n; i ++){
    		scanf("%d%d%d", &step2, &x, &y);
    		if((step2 - step1) < abs(lastx - x) + abs(lasty - y))flag = true;
    		else if((step2 - x - y) % 2)flag = true;
    		step1 = step2;
    		lastx = x;
    		lasty = y; 
    	}
    	
    	if(flag) puts("No");
    	else puts("Yes");
    	
    	return 0;
    } 
    

    B

    #include <stdio.h>
    #include <bits/stdc++.h>
    using namespace std;
    
    int T, A, B, Max = 0;
    bool v[5000005]; 
    
    int main(){
    	v[0]=true; 
    	
    	scanf("%d%d%d", &T, &A, &B);
    	
    	if(!(T % A)|| !(T % B)){
    		printf("%d
    ",T);
    		return 0;
    	}
    	
    	for(int i = A; i <= T; i ++) if(v[i - A])v[i] = 1;
    		
    	for(int i = B; i <= T; i ++) if(v[i - B])v[i] = 1;
    
    	for(int i = 1; i <= T; i ++) if(v[i]) v[i / 2] = true;	
    	
    	for(int i = A; i <= T; i ++) if(v[i - A])v[i] = 1;
    		
    	for(int i = B; i <= T; i ++) if(v[i - B])v[i] = 1;
    		
    	for(int i = T; i >= 1; i --){
    		if(v[i]){printf("%d",i);
                    return 0;
    	}
    	
    }
    

    C

    #include <stdio.h>
    #include <bits/stdc++.h>
    using namespace std;
    
    stack<int>S; 
    bool InStack[200005];
    int n, a, scc, tot;
    int VisitTime, MIN = 9999999;
    int End[200005], Last[200005], Next[200005];
    int low[200005], dfn[200005], Belong[200005];
    
    int Min(int a, int b){
    	return a < b ? a : b;
    }
    
    void tajian(int u){
    	int nonstop = 0;
    	low[u] = dfn[u] = ++ VisitTime;
    	S.push(u);
    	InStack[u] = true;
    	for(int i = Last[u]; i; i = Next[i]){
    		int v = End[i];
    		if(!dfn[v]){
    			tajian(v);
    			low[u] = Min(low[u], low[v]);
    		}
    		else if(InStack[v]){
    			low[u] = Min(low[u], low[v]);
    		}
    	}
    	if(dfn[u] == low[u]){
    		scc ++;
    		int v;
    		do{
    			v = S.top();
    			S.pop();
    			InStack[v] = false;
    			Belong[v] = scc;
    			nonstop ++;
    		}while(u != v);
    		if(nonstop != 1)MIN = Min(nonstop, MIN);
    	}
    }
    
    
    
    int main(){
    	scanf("%d", &n);
    	
    	for(int i = 1; i <= n; i ++){
    		scanf("%d", &a);
    		End[i] = a;
    		Next[i] = Last[i];
    		Last[i] = i;	
    	}
    	
    	for(int i = 1; i <= n; i ++)if(!dfn[i])tajian(i);
    	
    	printf("%d", MIN);
    }
    

    D

    #include <stdio.h>
    #include <bits/stdc++.h>
    using namespace std;
    
    char c; 
    int n, x;
    int posw[2005], posb[2005];
    int cntW[2005][2005],cntB[2005][2005],f[2005][2005];
    
    int main()
    {
    	memset(f,0x7f,sizeof(f));
    	
    	cin>>n;
    	
    	for(int i = 1; i <= 2 * n; i ++){
        	cin>>c>>x;
        	if(c == 'W') posw[x] = i;
        	else posb[x] = i;
    	}
    	
    	for(int i = 0; i <= n; i ++){//i从0开始! 
        	for(int j = 1; j < i; j ++) if(posw[i] < posw[j]) cntW[i][0] ++;
            for(int j = 1; j <= n; j ++) cntW[i][j] = cntW[i][j - 1] + (posw[i] < posb[j]);
        }
    
    	for(int i = 0; i <= n; i ++){
    		for(int j = 1; j < i; j ++) if(posb[i] < posb[j]) cntB[0][i] ++;
    		for(int j = 1; j <= n; j ++) cntB[j][i] = cntB[j - 1][i] + (posb[i] < posw[j]);
    	}
    
    	
    	f[0][0] = 0;//~赋~初~值~ 
    	
    	for(int i = 0; i <= n; i ++)
    		for (int j = 0; j <= n; j ++)
    	{
    		if(i)f[i][j] = min(f[i - 1][j] + cntW[i][j], f[i][j]);
    		if(j)f[i][j] = min(f[i][j - 1] + cntB[i][j], f[i][j]);
    	}
    	
    	printf("%d
    ",f[n][n]);
    	
    	return 0; 
    }
    
  • 相关阅读:
    北京初“探”,还是初“谈”
    hadoop集群安装(多机,非伪集群)
    iOS8下注冊push方式变更
    Linux文件编辑命令具体整理
    HDU 1260
    二叉树遍历(前序、中序、后序、层次、深度优先、广度优先遍历)
    关于Linux静态库和动态库的分析
    JavaScript特效之前进,后退(返回上一级)
    具体解释Hibernate中的事务
    iOS开发
  • 原文地址:https://www.cnblogs.com/qwqq/p/10895750.html
Copyright © 2020-2023  润新知