The 2016 ACM-ICPC Asia Dalian
题目 | A | B | C | D | E | F | G | H | I | J | K |
---|---|---|---|---|---|---|---|---|---|---|---|
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}
1−100级别,大概要二分
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 = a
和LCM(x,y) = b
如果没有就输出 No Solution
题解: 首先我们需要知道这样一个结论,如果i,j
是互质的,那么i + j 和 i*j
也是互质的。已知x + y = a
和 LCM(x, y) = b
,变形为x * y / gcd(x,y) = b
,设gcd(x,y) = k
,x = k * i
,y = k * j
所以得到了k * (i + j) = a
和k*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 = a
和LCM(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;
}