zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 184 题解

    ( ext{不一样的阅读体验})

    ABC184 简要题解

    A

    输入 (a,b,c,d),输出 (a imes c - b imes d)

    //Code by do_while_true
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define re register
    //#define int long long
    inline int Max(int x, int y) { return x > y ? x : y; }
    inline int Min(int x, int y) { return x < y ? x : y; }
    inline int Abs(int x) { return x < 0 ? ~x + 1 : x; }
    inline int read() {
    	int r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') {
    		if(ch == '-') w = 1;
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9') {
    		r = (r << 3) + (r << 1) + (ch ^ 48);
    		ch = getchar();
    	}
    	return w ? ~r + 1 : r;
    }
    //#undef int
    int a, b, c, d;
    signed main() {
    	a = read(); b = read(); c = read(); d = read();
    	printf("%d
    ", a*d - b*c);
    	return 0;
    }
    

    B

    根据题意模拟,每一次读入判断要加还是减。

    //Code by do_while_true
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define re register
    //#define int long long
    inline int Max(int x, int y) { return x > y ? x : y; }
    inline int Min(int x, int y) { return x < y ? x : y; }
    inline int Abs(int x) { return x < 0 ? ~x + 1 : x; }
    inline int read() {
    	int r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') {
    		if(ch == '-') w = 1;
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9') {
    		r = (r << 3) + (r << 1) + (ch ^ 48);
    		ch = getchar();
    	}
    	return w ? ~r + 1 : r;
    }
    //#undef int
    const int N = 2e5 + 10;
    int n, ans;
    char ch[N + 10];
    signed main() {
    	n = read(); ans = read();
    	scanf("%s", ch + 1);
    	for(int i = 1; i <= n; ++i) {
    		if(ch[i] == 'o') ++ans;
    		if(ch[i] == 'x' && ans) --ans;
    	}
    	printf("%d
    ", ans);
    	
    	return 0;
    }
    
    

    C

    分类讨论一下怎么走最优即可。

    //Code by do_while_true
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define re register
    //#define int long long
    inline int Max(int x, int y) { return x > y ? x : y; }
    inline int Min(int x, int y) { return x < y ? x : y; }
    inline int Abs(int x) { return x < 0 ? ~x + 1 : x; }
    inline int read() {
    	int r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') {
    		if(ch == '-') w = 1;
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9') {
    		r = (r << 3) + (r << 1) + (ch ^ 48);
    		ch = getchar();
    	}
    	return w ? ~r + 1 : r;
    }
    //#undef int
    const int N = 2e5 + 10;
    int a, b, c, d;
    signed main() {
    	a = read(); b = read(); c = read(); d = read();
    	if(a == c && b == d) {
    		puts("0");
    		return 0;
    	}
    	if(a + b == c + d || a - b == c - d || Abs(a - c) + Abs(b - d) <= 3) {
    		puts("1");
    		return 0;
    	}
    	if(((d-c) & 1) == ((b-a) & 1)) {
    		puts("2");
    		return 0;
    	}
    	if(Abs(c + d - a - b) <= 3) {
    		puts("2");
    		return 0;
    	}
    	if(Abs(Abs(a-b) - Abs(c-d)) <= 3) {
    		puts("2");
    		return 0;
    	}
    	if(Abs(a - c) + Abs(b - d) <= 6) {
    		puts("2");
    		return 0;
    	}
    	puts("3");
    	return 0;
    }
    
    

    下面才是正文(不会吧不会吧,不会真的有人ABC的前三题都要看题解的吗)


    D

    看到 (100) 的数据范围,考虑 (n^3) 的做法,显然是 (dp)(f_{i,j,k}) 代表第一种选了 (i) 个,第二种选了 (j) 个,第三种选了 (k) 个的概率。

    因为知道了选到 (i,j,k),代价就是 ((i+j+k-a-b-c)),期望就能根据概率推出来,而概率比期望更好 (dp),所以选择概率作为状态。

    这个时候就很好算了,显然的,可以从选第一种,选第二种,选第三种,这三种不同的选择方案转移而来,统计一下 (i,j,k) 其中有 (100) 的期望加起来即可。

    转移方程见代码。

    //Code by do_while_true
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define ld double
    #define re register
    //#define int long long
    inline int Max(int x, int y) { return x > y ? x : y; }
    inline int Min(int x, int y) { return x < y ? x : y; }
    inline int Abs(int x) { return x < 0 ? ~x + 1 : x; }
    inline int read() {
    	int r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') {
    		if(ch == '-') w = 1;
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9') {
    		r = (r << 3) + (r << 1) + (ch ^ 48);
    		ch = getchar();
    	}
    	return w ? ~r + 1 : r;
    }
    //#undef int
    const int N = 110;
    int a, b, c, d;
    ld f[N][N][N], ans;
    signed main() {
    	a = read(); b = read(); c = read();
    	for(int i = 1; i <= 100; ++i)
    		for(int j = 1; j <= 100; ++j)
    			for(int k = 1; k <= 100; ++k)
    				f[i][j][k] = -1;
    	f[a][b][c] = 1;
    	for(int i = a; i <= 100; ++i)
    		for(int j = b; j <= 100; ++j)
    			for(int k = c; k <= 100; ++k) {
    				if(i == a && j == b && k == c) continue;
    				f[i][j][k] = 0;
    				if(i > a && j != 100 && k != 100 && f[i-1][j][k] != -1) f[i][j][k] += f[i-1][j][k] * (i-1) / (i-1+j+k);
    				if(j > b && i != 100 && k != 100 && f[i][j-1][k] != -1) f[i][j][k] += f[i][j-1][k] * (j-1) / (i+j-1+k);
    				if(k > c && i != 100 && j != 100 && f[i][j][k-1] != -1) f[i][j][k] += f[i][j][k-1] * (k-1) / (i+j+k-1);
    				if(i == 100 || j == 100 || k == 100) ans += (i - a + j - b + k - c) * f[i][j][k];
    			}
    	printf("%.6lf
    ", ans);
    	return 0;
    }
    
    

    E

    直接广搜即可,有一个小优化就是每种类型的传送门只需要遍历一遍就行了,因为第一遍过后这一种的全部的传送门都会变成入过队的点。因为和这道题不一样,不是强制传送,所以每个点只入队的广搜是正确的。时间复杂度为 (mathcal{O}(HW))

    //Code by do_while_true
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #define ll long long
    #define ld double
    #define re register
    #define pb push_back
    //#define int long long
    inline int Max(int x, int y) { return x > y ? x : y; }
    inline int Min(int x, int y) { return x < y ? x : y; }
    inline int Abs(int x) { return x < 0 ? ~x + 1 : x; }
    inline int read() {
    	int r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') {
    		if(ch == '-') w = 1;
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9') {
    		r = (r << 3) + (r << 1) + (ch ^ 48);
    		ch = getchar();
    	}
    	return w ? ~r + 1 : r;
    }
    //#undef int
    const int N = 2010;
    const int INF = 0x3f3f3f3f;
    int n, m, sx, sy, f[N][N];
    char ch[N][N];
    bool vis[N][N];
    bool viss[27];
    struct Point {
    	int x, y;
    	Point(int xx, int yy) { x = xx; y = yy; }
    };
    int dx[] = {0, 0, 1, -1};
    int dy[] = {1, -1, 0, 0}; 
    std::queue<Point>q;
    std::vector<Point>vec[27];
    signed main() {
    	n = read(); m = read();
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j) {
    			std::cin >> ch[i][j];
    			if(ch[i][j] == 'S') {
    				q.push(Point(i, j));
    				vis[i][j] = 1;
    			}
    			if(ch[i][j] >= 'a' && ch[i][j] <= 'z') vec[ch[i][j]-'a'].pb(Point(i, j));
    			if(ch[i][j] == 'G') {
    				sx = i;
    				sy = j;
    			}
    		}
    	while(!q.empty()) {
    		Point now = q.front(); q.pop();
    		int x = now.x, y= now.y;
    		if(f[sx][sy]) break;
    		for(int i = 0; i < 4; ++i) {
    			int tx = x + dx[i], ty = y + dy[i];
    			if(ch[tx][ty] == '#' || vis[tx][ty] || tx < 1 || ty < 1 || tx > n || ty > m) continue;
    			q.push(Point(tx, ty));
    			vis[tx][ty] = 1;
    			f[tx][ty] = f[x][y] + 1;
    		}
    		if(ch[x][y] >= 'a' && ch[x][y] <= 'z') {
    			int pos = ch[x][y] - 'a', siz = vec[pos].size();
    			if(viss[pos]) continue;
    			viss[pos] = 1;
    			for(int i = 0; i < siz; ++i) {
    				int tx = vec[pos][i].x, ty = vec[pos][i].y;
    				if(!vis[tx][ty]) {
    					q.push(Point(tx, ty));
    					vis[tx][ty] = 1;
    					f[tx][ty] = f[x][y] + 1; 
    				}
    			}
    		}
    	}
    	printf("%d
    ", f[sx][sy] == 0 ? -1 : f[sx][sy]);
    }
    

    F

    第一眼:这玩意不是NPC吗怎么可能解决。

    看到 (Nleq 40),哦,折半搜索啊。

    把集合分成两个同等大小的集合,对其中一个集合进行爆搜/状压求出每一种子集的总和,排一下序。

    对另一个集合进行爆搜/状压每一种子集的总和,在第一个集合的每一个子集的总和中二分出最优的方案,更新答案。

    时间复杂度 (mathcal{O}(2^{frac{N}{2}}log {N}))

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define re register
    #define int long long
    inline int Max(int x, int y) { return x > y ? x : y; }
    inline int Min(int x, int y) { return x < y ? x : y; }
    inline int Abs(int x) { return x < 0 ? ~x+1 : x; }
    inline int read() {
    	re int r = 0; re bool w = 0; re char ch = getchar();
    	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : w, ch = getchar();
    	while(ch >= '0' && ch <= '9') r = (r << 3) + (r << 1) + (ch ^ 48), ch = getchar();
    	return w ? ~r+1 : r;
    }
    #undef int
    const int N = 41;
    int n, cnt1, cnt2, cnt;
    ll T, a[N], b[N], c[N], ans;
    ll d[2100000];
    signed main() {
    	n = read(); T = read();
    	for(int i = 1; i <= n; ++i) a[i] = read();
    	cnt1 = n / 2; cnt2 = n - cnt1;
    	for(int i = 1; i <= cnt1; ++i) b[i] = a[i];
    	for(int i = 1; i <= cnt2; ++i) c[i] = a[n-i+1];
    	for(int i = 0; i <= (1 << cnt1) - 1; ++i) {
    		++cnt;
    		for(int j = 1; j <= cnt1; ++j)
    			if((1 << (j-1)) & i)
    				d[cnt] += b[j];
    	}
    	std::sort(d + 1, d + cnt + 1);
    	for(int i = 0; i <= (1 << cnt2) - 1; ++i) {
    		ll now = 0;
    		for(int j = 1; j <= cnt2; ++j)	
    			if((1 << (j-1)) & i)
    				now += c[j];
    		if(now > T) continue;
    		int pos = std::upper_bound(d + 1, d + cnt + 1, T - now) - d;
    		--pos;
    		ans = Max(ans, now + d[pos]);
    	}
    	printf("%lld
    ", ans);
    }
    
  • 相关阅读:
    操作系统:DOS
    袁氏-人物:袁淑
    移植linux-2.6.32.2到qq2440
    qq2440启动linux后出现错误提示request_module: runaway loop modprobe binfmt-464c
    qq2440启动linux后插入u盘出现usb 1-1: device descriptor read/64, error -110,usb 1-1: device not accepting address 8, error -110
    ubuntu14.04 64bit安装teamviewer
    vi 的使用
    添加了环境变量,然而交叉编译器还是无法运行的解决方案
    linux下route命令使用实战
    ubuntu14.04纯命令行下连接有线网和无线网
  • 原文地址:https://www.cnblogs.com/do-while-true/p/14075300.html
Copyright © 2011-2022 走看看