2016ACM/ICPC亚洲区大连站【solved:10 / 11】
2017-10-06 15:39
501 查看
hdu 5971 Wrestling Match(二分图染色)
题意: 给出 n 个人,m 场 比赛 x 个已经确定的好人 y 个已经确定的坏人。每场比赛都是好人和坏人对决。问是否能够将每个人划分成好人或者坏人。思路:建图以后,把已知的好人坏人跑一遍dfs,染色染下去,最后对剩下的尚未染色的进行二分图染色即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 1000 + 5; vector<int>G[maxn]; vector<int>good, bad; int ok; int col[maxn]; void dfs(int cur, int pa) { for(auto v : G[cur]) if(v != pa) { if(col[v] == col[cur]) ok = 0; else if(col[v] == 0) { col[v] = 3 - col[cur]; dfs(v, cur); } } } bool bipartite(int cur) { for(auto o : G[cur]) { if(col[o] == col[cur]) { ok = 0; return false; } if(col[o] == 0) { col[o] = 3 - col[cur]; if(!bipartite(o)) { ok = 0; return false; } } } return true; } int main() { int n, m, x, y; while(~scanf("%d%d%d%d", &n, &m, &x, &y)) { for(int i = 1; i <= n; i++) G[i].clear(), col[i] = 0; good.clear 4000 (), bad.clear(); for(int i = 0; i < m; i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } for(int i = 0; i < x; i++) { int u; scanf("%d", &u); good.push_back(u); } for(int i = 0; i < y; i++) { int u; scanf("%d", &u); bad.push_back(u); } ok = 1; for(auto o : good) { col[o] = 1; dfs(o, -1); } for(auto o : bad) { if(col[o] == 0) col[o] = 2; else if(col[o] == 1) ok = 0; dfs(o, -1); } for(int i = 1; i <= n; i++) { if(G[i].size() == 0) continue; if(col[i] == 0) { col[i] = 1; bipartite(i); } } for(int i = 1; i <= n; i++) { if(col[i] == 0) ok = 0; } if(ok) puts("YES"); else puts("NO"); } return 0; }
hdu 5972 Regular Number(类dp(所谓shift-and?)
题意:给你N位数,接下来有N行,第i行先输入n,表示这个数的第i 位上可以在接下来的n个数中挑选,然后i 行再输n个数。然后输入需要匹配的母串S,让你输出母串中有多少个可行的N位子串。(1≤N≤1000),(|S|≤5e6)思路:emmm我没注意是不是shift-and。感觉就是一种类似dp的思想啊,维持dp[len],长度为len的是否合法。然后每次检测新的长度的时候只需要把dp[len] &= dp[len - 1]即可。然后如果dp[n-1]==1,说明有个解了,更新一下答案即可。最后是利用bitset优化整个过程。
#include <bits/stdc++.h> using namespace std; const int maxn = 5e6 + 5; bitset<1005>num[10]; bitset<1005>ans; char s[maxn]; int main() { int n; while(~scanf("%d", &n)) { for(int i = 0; i < 10; i++) num[i].reset(); ans.reset(); for(int i = 0; i < n; i++) { int a; scanf("%d", &a); while(a--) { int x; scanf("%d", &x); num[x].set(i); } } getchar(); gets(s); int len = strlen(s); for(int i = 0; i < len; i++) { int temp = s[i] - '0'; ans = ans << 1; ans[0] = 1; ans &= num[temp]; if(ans[n-1]) { char ch = s[i + 1]; s[i+1] = '\0'; puts(s+i-n+1); s[i+1] = ch; } } } return 0; }
hdu 5973 Game of Taking Stones(威佐夫博弈模板题+高精度)
题意:威佐夫博弈模板题,输入数据10100。思路:拿java写高精度。emmm第一次写比较emmmm。很多点要注意啊。
import java.util.*; import java.math.*; public class Main { public static void main(String[] args) { BigDecimal one = new BigDecimal(1); BigDecimal two = new BigDecimal(2); BigDecimal five = new BigDecimal(5); BigDecimal lb = new BigDecimal(2); BigDecimal rb = new BigDecimal(3); for(int i = 0; i < 1000; i++) { BigDecimal mid = lb.add(rb).divide(two); if(mid.multiply(mid).compareTo(five) < 0) lb = mid; else rb = mid; } BigDecimal goldCut = lb.add(one).divide(two); BigDecimal a, b; Scanner input = new Scanner(System.in); while(input.hasNext()) { a = input.nextBigDecimal(); b = input.nextBigDecimal(); if(a.compareTo(b) > 0) { BigDecimal temp = a; a = b; b = temp; } b = b.subtract(a).multiply(goldCut); b = b.setScale(0, BigDecimal.ROUND_DOWN); if(a.compareTo(b) == 0) System.out.println(0); else System.out.println(1); } } }
hdu 5974 A Simple Math Problem(简单数论)
题意:给你a和b,找到一对x和y使得x+y==a,lcm(x,y)==b。数据1e9。思路:令g=gcd(x,<
1a109
/span>y),则x=k1g,y=k2g并且gcd(k1,k2)==1。
则已知的可以转化成
(k1+k2)∗g=a
k1k2g=b
若gcd(k1,k2)=1。则gcd((k1+k2),k1k2)=1
上面这个是可以证的。具体是证明,加和和k1和k2分别互质,所以和他们的乘积互质。
然后利用这个结论可以得到,g=gcd(a,b),然后可以得到一个方程,解方程即可。
#include <bits/stdc++.h> using namespace std; const double pi = acos(-1.0); long long Zcsqrt(long long x) { long long temp = sqrt(x); temp = max(0LL, temp - 5); while((temp + 1) * (temp + 1) <= x) temp++; return temp; } int main() { int a, b; while(~scanf("%d%d", &a, &b)) { int g = __gcd(a, b); int he = a / g; int cheng = b / g; long long delta = 1LL * he * he - 4LL * cheng; if(delta < 0) puts("No Solution"); else { long long temp = Zcsqrt(delta); if(temp * temp != delta) puts("No Solution"); else { long long tt1 = he + temp; long long tt2 = he - temp; if(tt1 & 1) puts("No Solution"); else { long long kk11 = tt2 / 2; long long kk21 = he - kk11; printf("%lld %lld\n", kk11 * g, kk21 * g); } } } } return 0; }
hdu 5975 Aninteresting game(树状数组)
题意:有n个集合,第 i 个集合的数是[i-lowbit(i)+1,i-1]+i;有m个询问,询问方式有两种,第一种方式是集合[a,b]共有多少个数?第二种方式是数字x在几个集合里面?(n≤1e18,q≤1e5)思路:理解树状数组原理的话,这题挺简单的…你会发现每次需要操作的数量刚好就是lowbit(x),那么op1可以用前缀和维护一下,op2就是普通树状数组跳一跳就行了。
#include <bits/stdc++.h> using namespace std; long long n, q, mi[105]; long long lowbit(long long x){return x&-x;} long long solve(long long x) { long long ret = 0; for(int i = 1; i < 63; i++) { if(x / mi[i-1] == 0) break; ret += (x / mi[i-1] - x / mi[i]) * mi[i-1]; } return ret; } int main() { mi[0] = 1; for(int i = 1; i < 63; i++) mi[i] = mi[i-1] * 2; while(~scanf("%lld%lld", &n, &q)) { while(q--) { int ty; long long x, y; scanf("%d", &ty); if(ty == 1) { scanf("%lld%lld", &x, &y); printf("%lld\n", solve(y) - solve(x - 1)); } else { scanf("%lld", &x); long long ans = 0; while(x <= n) { x += lowbit(x); ans++; } printf("%lld\n", ans); } } } return 0; }
hdu 5976 Detachment(贪心)
题意: 给定一个自然数x,让你给出一种拆分方式x=a1+a2+⋯(两两两各不相同),使得每个小部分的乘积s=a1∗a2∗⋯最大(x≤1e9,1e6组测试数据)思路:很容易发现贪心策略,找到一个2为首项的等差数列,加和不大于x。然后把剩下的部分给等差数列从大到小依次的加,然后我们会发现这个大概是一个log(n)的操作。由于测试数据极多,显然会T。那么我们发现可以使用数学公式计算出答案,然后推推公式,瞎比写就行啦。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int mod = 1e9 + 7; const int maxn = 1e6 + 5; long long Zcsqrt(long long x) { long long temp = sqrt(x); temp = max(0LL, temp - 5); while((temp + 1) * (temp + 1) <= x) temp++; return temp; } LL fac[maxn], invf[maxn]; LL quickpow(LL a, LL b, LL Mod) { LL ret = 1; while(b) { if(b & 1) ret = ret * a % Mod; b >>= 1; a = (a * a) % Mod; } return ret; } void init() { int limit = 1000000; fac[0] = 1; for(int i = 1; i < maxn; i++) fac[i] = i * fac[i - 1] % mod; invf[limit] = quickpow(fac[limit], mod - 2, mod); for(int i = limit - 1; i >= 0; i --) invf[i] = invf[i + 1] * (i + 1) % mod; } int main() { init(); int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); if(n <= 4) { printf("%d\n", n); continue; } long long temp = Zcsqrt(9LL + 8LL * n); temp = temp - 1; temp /= 2; temp = max(0LL, temp - 5); while((temp + 1+ 2) * (temp + 1- 1) <= 2LL * n) temp++; long long sum = (temp + 2) * ( temp - 1) / 2; long long delta = n - sum; int head = 2, tail = temp; long long times = delta / (temp - 1); head += times, tail += times; delta = delta - times* (temp - 1); int mr = tail - delta + 1; int ml = mr - 1; long long ans = fac[ml] * invf[head-1] % mod; mr++, tail++; ans = (ans * fac[tail] % mod * invf[mr-1]) % mod; printf("%lld\n", ans); } return 0; }
hdu 5977 Garden of Eden(树分治)
题意:给一棵节点数为n,节点种类为k的无根树,问其中有多少种不同的简单路径,可以满足路径上经过所有k种类型的点?(a->b与b->a算作两条路径,起点与终点也可以相同)。n≤1e5,k≤10。思路:我们思考如果针对,过根节点的路径该怎么处理。我们显然处理出来所有从根结点到各个结点的路径的状态。随便搜一下就行了,然后我们就能知道类似例题1中的depth[u]+depth[v],我们枚举类似depth[u]的路径状态,然后去找到有几条路径状态能和他或起来得到maxState。这时候枚举子集即可,maxState^子集就是depth[v]了。那么我们就能把calc函数写完,如果你搞懂了例题1的话,就会发现直接套一层一样的东西即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 50000 + 5; int n, k, root, a[maxn], siz[maxn], f[maxn], done[maxn]; vector<int>G[maxn]; //找一个点:删去后,使得最大树 最小。 int getRoot(int u, int fa) { siz[u] = 1, f[u] = 0; for(auto v: G[u]) if(v != fa && !done[v]) { siz[u] += getRoot(v, u); f[u] = max(f[u], siz[v]); } f[u] = max(f[u], f[0] - f[u]); if(f[u] < f[root]) root = u; return siz[u]; } vector<int>vec; void dfs_state(int cur, int fa, int state) { vec.push_back(state); for(auto v :G[cur]) if(v != fa && !done[v]) { dfs_state(v, cur, state | (1 << a[v])); } } int maxState, cnt[(1<<10) + 5]; long long calc(int cur, int paState) { vec.clear(); dfs_state(cur, -1, paState | (1 << a[cur])); for(int i = 0; i <= maxState; i++) cnt[i] = 0; for(auto o : vec) cnt[o]++; long long ret = 0; for(auto S : vec) { ret += cnt[maxState]; for(int i = S; i >= 1; i = (i - 1) & S) { ret += cnt[maxState ^ i]; } } return ret; } long long ans; void solve(int cur) { ans += calc(cur, 0); done[cur] = 1; for(auto v : G[cur]) { if(done[v]) continue; ans -= calc(v, (1 << a[cur])); f[0] = siz[v]; getRoot(v, root = 0); solve(root); } } int main() { while(~scanf("%d%d", &n, &k)) { for(int i = 1; i <= n; i++) done[i] = 0, G[i].clear(); for(int i = 1; i <= n; i++) scanf("%d", &a[i]), a[i]--; maxState = (1 << k) - 1; for(int i = 0; i < n - 1; i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } if (k == 1) { printf("%lld\n", 1LL * n * n); continue; } f[0] = n; getRoot(1, root=0); ans = 0; solve(root); printf("%lld\n", ans); } return 0; }
hdu 5978 To begin or not to begin
题意:给出 n 个黑球,一个红球。抽出红球胜利。如果先手有优势 输出 1 没有优势 输出 2 机会均等输出 0思路:随便算算就发现….每一次抽都是等概率获胜的,看一下奇偶性,也就是两个人各自抽了几次即可。
hdu 5979 Convex
题意:一个凸多边形每个顶点到其原点的距离相等,且能把该多边形分成几个部分,给定每个部分的角度,求多边形面积。思路:…两边夹一角算三角形会吗,加和即可。
hdu 5980 Find Small A
题意:给N个数 每个数都可以拆开成一个32位的2进制 每八位一个字节 每个字节的2进制数换算成十进制的看有多少个97思路:进制转换。water。
相关文章推荐
- 2016-2017 ACM-ICPC, NEERC, Central Subregional Contest【solved : 10 / 11】
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛【solved:9 / 10】
- 2016ACM/ICPC亚洲区大连站 J - Find Small A
- 2016ACM/ICPC亚洲区大连站-重现赛(感谢大连海事大学)(7/10)
- 2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest (ECPC 16)【solved:9 / 11】
- 2017 ACM/ICPC Asia Regional Qingdao Online【solved:7 / 11】
- HDU 5979 Convex【计算几何】 (2016ACM/ICPC亚洲区大连站)
- hdu5972 快速匹配bitset优化(shiftand算法)2016ACM/ICPC亚洲区大连站
- ACM-ICPC 2016亚洲区域赛(沈阳站)游记(滚粗记)
- 2016ACM/ICPC亚洲区青岛站【solved:5 / 13】
- Wrestling Match 2016ACM/ICPC亚洲区大连站-重现赛(感谢大连海事大学)hdu 5971
- hdu 5975 树状数组原理题(2016ACM/ICPC亚洲区大连站)
- 2016ACM/ICPC亚洲区大连站 D - A Simple Math Problem(尚未通过)
- 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2)【solved:12 / 13】
- 2016ACM/ICPC亚洲区大连站-重现赛
- 2017ACM/ICPC亚洲区沈阳站【solved:6 / 13】
- ACM-ICPC (10/11)
- HDU 5952 Counting Cliques 爆搜+剪枝+无向转单调有向 2016ACM/ICPC亚洲区沈阳站 E题
- 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) 【solved:9 / 12】
- HDU-5971 Wrestling Match (2016ACM/ICPC亚洲区大连站)