2016 ACM-ICPC Asia Dalian

The 2016 ACM-ICPC Asia Dalian

题目ABCDEFGHIJK
solved-🚫-🚫-

✔:比赛时通过;🚫:赛后通过;⚪:比赛时尝试了未通过;-:比赛时未尝试


A - Wrestling Match【二分图染色】

sloved by Sstee1XD. 0:55(+3)

题意:有n个选手构成对抗关系,每组对抗关系会分出 g o o d good good b a d bad bad两种选手。现在已知几个 g o o d good good选手和 b a d bad bad选手,问你是否能把所有选手准确地分成 g o o d good good b a d bad bad两类选手。

题解 :我们从已经分出来的选手出发,对其进行染色。注意有些选手和其他选手是没有对抗关系的,对于这些选手要判断下是否已经提前分好类。
(由于现场代码写得过于丑陋,甚至wa了三发,所以没交现场代码QAQ

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e3 + 7;
int n, m, x, y;
vector<int> G[maxn];
int cor[maxn];
int dfs(int u, int c) {
    cor[u] = c;
	for (auto v : G[u]) {
        if (cor[v] == c) return 0;
		if (!cor[v] && !dfs(v, -c)) return 0;
	}
	return 1;
}
void run() {
	for (int i = 1; i <= n; ++i) G[i].clear();
	for (int i = 1, u, v; i <= m; ++i) {
		scanf("%d %d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	memset(cor, 0, sizeof(cor));
	for (int i = 1, u; i <= x; ++i) {
		scanf("%d", &u);
		cor[u] = 1;
	}
	for (int i = 1, u; i <= y; ++i) {
		scanf("%d", &u);
		cor[u] = -1;
	}
	for (int i = 1; i <= n; ++i) {
		if (cor[i] && !dfs(i, cor[i]) || !cor[i] && !G[i].size()) {
			puts("NO");
			return;
		}
	}
	for (int i = 1; i <= n; ++i) {
		if (!cor[i] && !dfs(i, 1) && !dfs(i, -1)) {
			puts("NO");
			return;
		}
	}
	puts("YES");
}

int main() {
	while (~scanf("%d %d %d %d", &n, &m, &x, &y)) run();
    return 0;
}

C - Game of Taking Stones

Solved by Sstee1XD. (-)

题解: 大数威佐夫博弈,我们采用java高精度来写。求 5 + 1 \sqrt{5} + 1 5 +1时采用二分来求,注意要求到 l l l r r r直接差值要到 1 − 100 1^{-100} 1100级别,大概要二分 300 300 300多次,这里直接二分 500 500 500次。

import java.math.BigDecimal;
import java.util.Scanner;

public class Main {
	static BigDecimal n, m;
	static BigDecimal two = new BigDecimal("2");
	static BigDecimal five = new BigDecimal("5");
	static BigDecimal c = init().divide(two);
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		while (in.hasNext()) {
			n = new BigDecimal(in.next());
			m = new BigDecimal(in.next());
			if (n.compareTo(m) < 0) {
				BigDecimal tmp;
				tmp = n;
				n = m;
				m = tmp;
			}
			n = n.subtract(m).multiply(c);
			n = n.setScale(0, BigDecimal.ROUND_DOWN);
			if (n.equals(m) == true) {
				System.out.println("0");
			}
			else System.out.println("1");
		}
	}
	
	static BigDecimal init() {
		BigDecimal l = new BigDecimal("2");
		BigDecimal r = new BigDecimal("3");
		BigDecimal mid = null;
		for (int i = 1; i <= 500; ++i) {
			mid = l.add(r).divide(two);
			if (mid.multiply(mid).compareTo(five) <= 0) {
				l = mid;
			}
			else r = mid;
		}
		return mid.add(new BigDecimal("1"));
	}
	
}

D - A Simple Math Problem

solved by Tryna. 2:57(+1)

题意: 给出a和b,找到了一组x和y,满足x + y = aLCM(x,y) = b如果没有就输出 No Solution

题解: 首先我们需要知道这样一个结论,如果i,j是互质的,那么i + j 和 i*j也是互质的。已知x + y = aLCM(x, y) = b,变形为x * y / gcd(x,y) = b,设gcd(x,y) = kx = k * iy = k * j所以得到了k * (i + j) = ak*i*j = b,因为i,j互质,所以i + j, i * j互质,所以gcd(a,b) = k = gcd(x,y)。知道了这个就很好写了,我们有两个方程,分别是x + y = a 和 x * y = k * b,我们采用代入消元法消去y,就得到了x^2 - a*x + k*b = 0,然后就采用求根公式求解,求出来的解也必须要满足x + y = aLCM(x,y) = b,这里没考虑周到白给了一发。

#include<bits/stdc++.h>
using namespace std;
long long gcd(long long a, long long b) {	return a == 0 ? b : gcd(b%a, a);}
long long lcm(long long a, long long b) { return a * b / gcd(a, b);}
typedef long long ll;
long long a, b;
int main() {
	while(~scanf("%lld %lld", &a, &b)){
		long long k = gcd(a, b);
		long long deta = a * a - 4 * b * k;
		if(deta < 0) puts("No Solution");
		else{
			long long x1 = (a - sqrt(deta)) / (long long)2;
			long long x2 = (a + sqrt(deta)) / (long long)2;
			if(x1 + x2 != a) puts("No Solution");
			else if(lcm(x1, x2) != b) puts("No Solution");
			else printf("%lld %lld\n", x1, x2);
		}
	}
    return 0;
}

F - Detachment

solved by Tryna. (-)

题意: 给出一个数,将它拆分成若干个数的和,并且这些数不能重复,求这若干个数的积的最大值

题解: 通过枚举前面的一些数我们不难发现此题的贪心策略,首先1肯定不能取,因为1对积没有贡献,并且还占用和。贪心策略是从2开始连续的数字相乘,比如, 9最优的情况就是2 * 3 * 4,14最优的情况就是2 * 3 * 4 * 5,但并不是所有数字都能凑出这样的形式,那么对于9到14之间的数字我们这样处理,比如说11,它比9大2,我们就从后往前每个数字加1,就得到了2 * 4 * 5这样的最优情况。想出贪心策略的时候我就冲了一发,结果毫无疑问TLE了。赛后看了大佬们的博客,用了 前缀和 + 前缀积 + 逆元 优化。分两种情况,第一种情况 比如2 * 3 * 4 * 5 余5和最后一个数相等, 3 * 4 * 5 * 7 就是每个数都加一遍,然后给最后一个数在加1, 就是 5的阶乘除以2 乘上(p + 2)(p是最后一个数); 第二种情况 比如 2 * 3 * 4 * 5 余2,那就从后往前每个数加1,直到加完 2 * 3 * 5 * 6, 总结就是 3的阶乘 乘上 6的阶乘 除 4的阶乘 因为有除法,所以我们需要把除法转化成乘法逆元。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 5e4 + 5;
const int Mod = 1e9 + 7;
typedef long long ll;
ll mul[maxn], sum[maxn];
void init(){
    mul[1] = 1;  
    sum[1] = 0;
    for(int i = 2; i <= maxn; i++){
        sum[i] = sum[i-1] + i;
        mul[i] = (i*mul[i-1]) % Mod;
    }
}
ll inv(ll a, int b){
    ll ans = 1;
    while(b)
    {
        if(b&1) ans = (ans*a) % Mod;
        a = (a*a) % Mod;
        b >>= 1;
    }
    return ans;
}

int t, x;

int main(){
    scanf("%d", &t);
    init();
    while(t--){
        scanf("%d", &x);
        if(x == 1){
            puts("1");
            continue;
        }
        int l = 2, r = maxn, mid, p;
        while(l <= r){
            mid = (l + r) / 2;
            if(sum[mid] <= x){
                p = mid;
                l = mid + 1;
            }
            else r = mid - 1;
        }
        int num = x - sum[p];
        ll ans = 0;
        if(num == p) ans = (mul[p] * inv(2, Mod - 2) % Mod * (p + 2) % Mod) % Mod;
        else ans = (mul[p + 1] * inv(mul[p - num + 1], Mod - 2) % Mod * mul[p - num] % Mod) % Mod;
        printf("%lld\n", ans);
    }
    return 0;
}

H - To begin or not to begin【简单博弈】

solved by lllllan. 01:19(+1)

题意: k 个黑球和1个红球,两个轮流抽,抽到红球算赢,问先手赢的概率大还是后手大,还是概率相等?

#include<bits/stdc++.h>
using namespace std;

int k;
int main() {
	while(~scanf("%d", &k)){
		if(k % 2) puts("0");
		else puts("1");
	}
    return 0;
}

I - Convex

solverd by Tryna. 0:29(+1)

题意: 一个圆上有n个点,每个点和原点相连,给出他们的角度,求这个图形的面积。

题解: 每部分都是个三角形,用三角形面积公式就结束了。写太快了导致写呲了,白给一发。 S = 1/2 * a * b * sin(angle)

#include<bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
int n;
double d, angle, sum;
int main() {
	while(~scanf("%d %lf", &n, &d)){
		sum = 0;
		for(int i = 1; i <= n; i++){
			scanf("%lf", &angle);
			angle = angle * (pi / 180);
			sum += d * d / 2.0 * (sin(angle));
		}
		printf("%.3f\n", sum);
	}	
    return 0;
}

J - Find Small A【位运算】

solved by lllllan. 02:59(+7)【通过7次尝试才能读懂题意是真的没谁了】

题意: 给N个数 每个数都可以拆开成一个32位的2进制 每八位一个字节 每个字节的2进制数换算成十进制的看有多少个97

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, k;
ll a;
int main() {
	scanf("%d", &n);
	int sum = 0;
	while(n--){
		scanf("%lld", &a);
		while(a){
			if(a % 256 == 97) sum++;
			a >>= 8;
		}
	}
	printf("%d\n", sum);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值