• 2021.10.17CSP模拟赛 赛后总结


    这一场个人感觉考得还是很不错的,至少能拿的分都拿了。

    A. [SCOI2009]生日快乐

    乍一看以为是一道数学题,然后看到下面的数据范围:(1 leq N leq 10)

    突然发现写个爆搜就可以了(其实还是想了很长时间 QwQ)。

    我们存 3 个变量 (dfs(x, y, k)) 表示在 (x * y) 的矩形中切 (k) 刀,长和宽最小比例最大是多少。

    我们枚举切几刀,然后上下左右都要搜一遍,求个最大值即可。

    代码十分简洁。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    double n, m;
    int k;
    
    inline double dfs(double x, double y, int k){
    	if(k == 1) return max(x / y, y / x);
    	double res = 1e9;
    	for(int i = 1; i <= (k >> 1); i++){
    		double tx = x * i / k, ty = y * i / k;
    		res = min(res, max(dfs(tx, y, i), dfs(x - tx, y, k - i)));
    		res = min(res, max(dfs(x, ty, i), dfs(x, y - ty, k - i)));
    	}
    	return res;
    }
    
    int main(){
    	scanf("%lf%lf%d", &n, &m, &k);
    	printf("%.6lf
    ", dfs(n, m, k));
    	return 0;
    }
    

    B.「POI2011 R2 Day1」垃圾运输 Garbage

    emm……这道题考场上看了一眼,觉得有点困难,所以就先弃了,去看 (T3) 了,最后也没时间写了,后来发现这道题可能比 (T3) 好想一点,但是不好写……

    而且内部 (oj)(spj) 有锅,在洛谷上能 (AC) 的代码交上去只有 52 分(还好没写)。

    下面进入正文:

    我们发现对于当前颜色和目标颜色一样的边不需要考虑,所以我们只把需要改变颜色的边加入到图里。

    然后其实就是找欧拉回路,也就是找环,然后就没别的了。

    提前判断一下如果有度数为奇数的点,直接输出 NIE

    (洛谷AC代码)

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    const int N = 1e5 + 10;
    const int M = 1e6 + 10;
    int n, m;
    struct node{
    	int v, nxt;
    }edge[M << 1];
    int head[N], tot = 1;
    int du[N], vis[M << 1];
    int stk[M], top;
    int cnt;
    
    inline void add(int x, int y){
    	edge[++tot] = (node){y, head[x]};
    	head[x] = tot;
    }
    
    inline void dfs(int x, int root){
    	stk[++top] = x;
    	du[x] -= 2;
    	for(int i = head[x]; i; i = edge[i].nxt){
    		head[x] = i;
    		if(vis[i]) continue;
    		vis[i] = vis[i ^ 1] = 1;
    		int y = edge[i].v;	
    		if(y == root && x != root){
    			cnt++;
    			stk[++top] = y;
    			return;
    		}
    		dfs(y, root);
    		return;
    	}
    }
    
    int main(){
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= m; i++){
    		int u, v, p, q;
    		scanf("%d%d%d%d", &u, &v, &p, &q);
    		if(p ^ q){
    			add(u, v), add(v, u);
    			du[u]++, du[v]++;
    		}
    	}
    	for(int i = 1; i <= n; i++)
    		if(du[i] & 1){
    			puts("NIE");
    			return 0;
    		}
    	for(int i = 1; i <= n; i++){
    		if(!du[i]) continue;
    		while(du[i]) dfs(i, i);
    	}
    	printf("%d
    ", cnt);
    	for(int i = 1; i <= top; i++){
    		int u = stk[i], k = 1;
    		i++; 
    		while(stk[i] != u && i <= top)
    			k++, i++;
    		printf("%d ", k);
    		for(int j = i - k; j <= i; j++)
    			printf("%d ", stk[j]);
    		puts("");
    	}
    	return 0;
    }
    

    C. [JSOI2010]快递服务

    一道非常巧妙的 (dp),考场上写了 3h,还好最后调出来了,心态没炸。

    考虑朴素的状态 (f[i][a][b][c]),应该很容易看出来含义。

    即,第 (i) 的个询问,三辆车分别在 (a,b,c) 三点时的最小油费。

    但是这样转移的话时间,空间都会爆炸,所以考虑优化。

    我们发现,对于上述状态,(a,b,c) 中必定有一个等于 (p[i]) 即当前询问的节点编号。

    所以我们可以压掉这一维,只用剩下两维进行转移,那么:

    设:(x) 为上一次询问的节点,(y) 为当前询问节点。

    (f[i][a][b] = min(f[i - 1][a]][b] + dis(x, y))) (上一次在 (x) 点的车走到 (y)

    (f[i][a][b] = min(f[i - 1][x][b] + dis(a, y))) (上一次在 (a) 点的车走到 (y)

    (f[i][a][b] = min(f[i - 1][a][x] + dis(b, y))) (上一次在 (b) 点的车走到 (y)

    然后本题应该就可以 (A) 了,因为题目给了 (1G) 的空间……

    但其实还可以滚动一下。

    我的代码强制 (f) 的第二维 (<) 第三维,其实可以不用。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    inline int read(){
    	int y = 0;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') y = (y << 3) + (y << 1) + ch - '0', ch = getchar();
    	return y;
    }
    
    const int N = 210;
    const int M = 1010;
    int dis[N][N], f[2][N][N];//f[i][x][y] (x <= y)
    int n, y, cnt, ans = 1e9;
    int x, l;
    
    int main(){
    	// freopen("C.in", "r", stdin);
    	// freopen("C.out", "w", stdout);
    	n = read();
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= n; j++)
    			dis[i][j] = read();
    	memset(f, 0x3f, sizeof(f));
    	x = 1;
    	f[0][2][3] = 0;
    	while(scanf("%d", &y) != EOF){
    		l ^= 1;
    		memset(f[l], 0x3f, sizeof(f[l]));
    		cnt++;
    		// cout << cnt << " " << y << endl;
    		for(int i = 1; i <= n; i++)
    			for(int j = i; j <= n; j++){
    				f[l][i][j] = min(f[l][i][j], f[l ^ 1][i][j] + dis[x][y]);
    				if(x < j) f[l][x][j] = min(f[l][x][j], f[l ^ 1][i][j] + dis[i][y]);
    				else f[l][j][x] = min(f[l][j][x], f[l ^ 1][i][j] + dis[i][y]);
    				if(x < i) f[l][x][i] = min(f[l][x][i], f[l ^ 1][i][j] + dis[j][y]);
    				else f[l][i][x] = min(f[l][i][x], f[l ^ 1][i][j] + dis[j][y]);
    			}
    		x = y;
    	}
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= n; j++)
    			ans = min(ans, f[l][i][j]);
    	printf("%d
    ", ans);
    	return 0;
    }
    

    D. [HNOI2010]物品调度

    emm……还不会。

    考场上输出 (n - 1) 得了 10pts。

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15422614.html

  • 相关阅读:
    基于注解的IOC配置
    字符串典型问题分析
    指针与数组
    数组的本质
    数组与指针分析
    指针的本质
    #与##操作符使用
    #pragma使用分析
    #error和#line使用分析
    条件编译使用
  • 原文地址:https://www.cnblogs.com/xixike/p/15422614.html
Copyright © 2020-2023  润新知