Topcoder SRM548 Div 1
1. KingdomAndTrees
给出n个数a[1..n],求一个数组b[1..n]满足b严格递增,且b[1]>=1。
定义代价为W = max{abs(a[i]-b[i])},求代价最小值。
n<=50
【题解】
二分代价W,贪心判断。当前肯定越小越优,如果下一个加上当前二分的值,小于等于当前这个,那么就肯定不行,依次判即可。
// BEGIN CUT HERE // END CUT HERE
#line 5 "KingdomAndTrees.cpp"
# include <vector>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm> using namespace std; typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = + ;
const int INF = 1e9; class KingdomAndTrees {
public:
int n, h[M];
inline bool chk(int x) {
int lst = max(h[]-x, );
for (int i=; i<=n; ++i) {
if(h[i]+x <= lst) return false;
lst = max(h[i]-x, lst+);
}
return true;
}
int minLevel(vector<int> heights) {
int l = , r = 2e9, mid, ans;
n = heights.size();
for (int i=; i<n; ++i) h[i+] = heights[i];
while() {
if(r-l <= ) {
for (int i=l; i<=r; ++i)
if(chk(i)) {
ans = i;
break;
}
break;
}
mid = l+r>>;
if(chk(mid)) r = mid;
else l = mid;
}
return ans;
}
};
2. KingdomAndDice
给出n个数a[1..n],再给出n个数b[1..n],a中有些数为0,你要把其中一些0改成不大于X的数,满足:任意不大于X的正整数最多在a和b中共出现1次。
令p为随机选1<=i,j<=n,使得ai>bj的概率,求使|p-0.5|最小的p值。
n<=50
【题解】
看成贡献,每个ai>bj相当于贡献+1。就使得贡献和n*n/2最接近即可。
b数组把[0,X]分成了n+1段,a如果在第i段内的贡献为i-1,容易看出在第1段中一定可以不改(本来就是0),所以第1段忽略,其他往上整(现在就是在第i段内贡献为i)
考虑dp:f[i,j,k]表示在前i段中,有了j个0,贡献为k,是否可行。
那么枚举当前段选了几个。这个的上限可以通过预处理求得。
然后直接转移即可。时间复杂度O(n^5)
// BEGIN CUT HERE // END CUT HERE
#line 5 "KingdomAndDice.cpp"
# include <math.h>
# include <vector>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm> using namespace std; typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = + ;
const int INF = 1e9; class KingdomAndDice {
public:
bool f[M][M][M*M];
int n, a[M], b[M], len[M], m;
double newFairness(vector <int> firstDie, vector <int> secondDie, int X) {
memset(f, , sizeof f);
int pre = ;
n = firstDie.size(); m = ;
for (int i=; i<=n; ++i) {
a[i] = firstDie[i-];
b[i] = secondDie[i-];
m += (a[i] == );
}
sort(a+, a+n+);
sort(b+, b+n+);
// for (int i=1; i<=n; ++i) cout << a[i] << ' '; cout << endl;
// for (int i=1; i<=n; ++i) cout << b[i] << ' '; cout << endl;
for (int i=; i<n; ++i) len[i] = b[i+] - b[i] - ;
len[n] = X - b[n];
for (int i=; i<=n; ++i) {
if(a[i] == ) continue;
int tem = ;
for (int j=; j<=n; ++j)
if(a[i] > b[j]) ++tem;
if(tem) len[tem] --;
pre += tem;
}
// for (int i=1; i<=n; ++i) cout << len[i] << ' ';
// cout << endl;
for (int j=; j<=m; ++j) f[][j][pre] = ;
for (int i=; i<=n; ++i)
for (int j=; j<=m; ++j)
for (int k=; k<=n*n; ++k)
for (int cur=, to = min(j, len[i]); cur<=to; ++cur)
if(k-i*cur >= ) {
// if(f[i-1][j-cur][k-i*cur] == 1 && f[i][j][k] == 0)
// printf("f[%d,%d,%d] --> f[%d,%d,%d]\n", i-1, j-cur, k-i*cur, i, j, k);
f[i][j][k] |= f[i-][j-cur][k-i*cur];
}
double ans = 1e9, E = (double)n*n, id;
for (int i=; i<=n*n; ++i) {
if(f[n][m][i]) {
// cout << i << endl;
if(fabs(*i-E) < ans) {
ans = fabs(*i-E);
id = i;
}
}
}
return id/n/n;
}
};
这其实是一个多重背包,把枚举的那个部分用二进制拆分,然后用01背包做就能做到O(n^4logn)的复杂度。
发现是bool数组的转移,把转移用bitset维护,就能做到O(n^4logn/32)的复杂度。
其实状态也是可以优化的(可以不记录j这维,把bool数组改成int,存j),这样就能做到O(n^3logn)的复杂度,好像和bitset的复杂度差不多?
不管了反正n=50我就写O(n^5)
其他。。待填坑。
3.KingdomAndCities
求n个点m条边,前K个点度数均为2的无向连通图的个数,无重边自环。
n,m<=50,K<=2
【题解】
考虑k=0的情况,就是求n个点m条边的无向连通图个数。
令f(i,j)表示i个点j条边的无向连通图个数。令E(i)表示i个点的无向完全图的边数。
考虑补集转换,全部方案为C(E(i),j)。
枚举第一个点包含的连通块的大小k以及里面的边l。
那么一种(k,l)对应的方案数有C(i-1,k-1)*C(E(i-k),j-l)*f[k][l]
从i-1个点(除了1)选出k-1个点跟1号点在一个连通块。另外一个部分连通不连通都行,方案就是C(E(i-k),j-l),然后乘上1号点包含的连通块个数。
总的方程式就是

那么我们会K=0的情况了。
下面的图红色表示即将被删除,蓝色表示即将被加入,黑色表示本来就有。
在讨论1<=K<=2的情况前,我们不妨思考这样一个结论:
在每种方案中,限定度数为2的点要么用来取代一个边,延长一个链,要么用来加到一个边的两个端点上,构成一个环。
特殊的,当K=2时候可能存在加到一个点上,构成三元环。
比如:

这种就不符合上面三种情况,所以这种情况可以看作1、3之间原来有边,用0来延长这条边。
类似的,所有其他不符合上面三种情况,都已经被上面两种情况包含的方案计算过了。
1. 对于K=1:
①延长链

从f[n-1,m-1]转移来,有m-1个边可以作为延长对象。
②构成环

从f[n-1,m-2]转移来,有m-1个边可以作为构成环的对象。
综上,我们完成了对K=1的分类讨论。实现见代码。
2. 对于K=2:
①两个连一起,延长链

从f[n-2,m-2]转移来,有m-2条边可以作为延长的对象,延长后0/1的摆放位置有2种(0前1后,0后1前)
②两个连一起,构成环

从f[n-2,m-3]转移来,有m-3条边可以作为构成环的对象,0/1的摆放位置同样有2种。
③延长两条边

从f[n-2,m-2]转移来,有(m-2)*(m-3)/2对组合可以加,0/1的摆放位置有2种。
④两个点分别构成环

从f[n-2,m-4]转移来,有(m-4)*(m-5)/2对组合可以加,0/1的摆放位置有2种。
⑤一个点构成环,一个点延长链

从f[n-2,m-3]转移来,有(m-3)*(m-4)/2对组合可以加,0/1的摆放位置有2种,构成环/延长链也有2种。
⑥在同一条边上构成2个环

从f[n-2,m-4]转移来,有m-4条边可以作为构成2个环的对象。由于对称不存在顺序。
⑦在同一条边上分别延长

从f[n-2,m-3]转移来,有m-3条边可以作为延长对象。由于对称不存在顺序。
⑧在一个点上构成一个环。
假设红色的那个点是本来存在的。

从f[n-2,m-3]转移来,有n-2个点可以作为成环对象。由于对称不存在顺序
我们终于讨论完K=2了!
然后就很简单了。。
// BEGIN CUT HERE // END CUT HERE
#line 5 "KingdomAndCities.cpp"
# include <vector>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm> using namespace std; typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = + , N = + ;
const int INF = 1e9, mod = 1e9 + ; class KingdomAndCities {
public:
int f[M][M];
int C[N][N]; inline int E(int n) { return n * (n-) / ; } int howMany(int n, int K, int m) { if(n == ) return (m== && K==);
if(n == ) return (m== && K==); C[][] = ;
for (int i=; i<=; ++i) {
C[i][] = ;
for (int j=; j<=i; ++j) {
C[i][j] = C[i-][j] + C[i-][j-];
if(C[i][j] >= mod) C[i][j] -= mod;
}
} for (int i=; i<=n; ++i)
for (int j=; j<=m; ++j) {
f[i][j] = C[E(i)][j];
for (int k=; k<=i-; ++k) {
int res = ;
for (int l=k-, lto = min(E(k), j); l<=lto; ++l) {
res = res + 1ll * C[E(i-k)][j-l] * f[k][l] % mod;
if(res >= mod) res -= mod;
}
res = 1ll * res * C[i-][k-] % mod;
f[i][j] -= res;
if(f[i][j] < ) f[i][j] += mod;
}
} // f(n,m) 表示n个点m条边的无向连通图的个数 if(K == ) return f[n][m]; ll ans = ;
if(K == ) {
// K = 1
if(m >= ) (ans += 1ll * f[n-][m-] * (m-) % mod) %= mod;
if(m >= ) (ans += 1ll * f[n-][m-] * (m-) % mod) %= mod;
} else {
// K = 2
if(m >= ) (ans += 1ll * f[n-][m-] * * (m-) % mod) %= mod;
if(m >= ) (ans += 1ll * f[n-][m-] * * (m-) % mod) %= mod;
if(m >= ) (ans += 1ll * f[n-][m-] * (m-) * (m-) % mod) %= mod;
if(m >= ) (ans += 1ll * f[n-][m-] * * (m-) * (m-) % mod) %= mod;
if(m >= ) (ans += 1ll * f[n-][m-] * (m-) * (m-) % mod) %= mod;
if(m >= ) (ans += 1ll * f[n-][m-] * (m-) % mod) %= mod;
if(m >= ) (ans += 1ll * f[n-][m-] * (m-) % mod) %= mod;
if(m >= ) (ans += 1ll * f[n-][m-] * (n-) % mod) %= mod;
if(m >= ) (ans += 1ll * f[n-][m-] * (m-) * (m-) % mod) %= mod;
}
return ans;
} };
Topcoder SRM548 Div 1的更多相关文章
- TopCoder[SRM513 DIV 1]:Reflections(1000)
Problem Statement Manao is playing a new game called Reflections. The goal of the game is trans ...
- Topcoder SRM584 DIV 2 500
#include <set> #include <iostream> #include <string> #include <vector> using ...
- Topcoder SRM583 DIV 2 250
#include <string> #include <iostream> using namespace std; class SwappingDigits { public ...
- 【补解体报告】topcoder 634 DIV 2
A:应该是道语文题,注意边界就好: B:开始考虑的太复杂,没能够完全提取题目的思维. 但还是A了!我愚蠢的做法:二分答案加暴力枚举, 枚举的时候是完全模拟的,比如每次取得时候都是从大到小的去取,最后统 ...
- Topcoder Srm627 DIV 2
A,B:很水,注意边界,话说HACK都是这些原因. C: R[I][J]:表示反转I-J能改变冒泡排序的次数: DP方程:dp[i][k]=max(dp[j][k],dp[j][k-1]+dp[j][ ...
- TopCoder[SRM587 DIV 1]:TriangleXor(550)
Problem Statement You are given an int W. There is a rectangle in the XY-plane with corners at ...
- TopCoder[SRM587 DIV 1]:ThreeColorability(900)
Problem Statement There is a H times W rectangle divided into unit cells. The rows of cells are ...
- TopCoder[SRM513 DIV 1]:PerfectMemory(500)
Problem Statement You might have played the game called Memoria. In this game, there is a board ...
- [topcoder]BinaryCards
现在觉得有空时可以刷一下topcoder的DIV 2的Lvl 3的题目.感觉和刷LeetCode和WikiOi都是不一样的. http://community.topcoder.com/stat?c= ...
随机推荐
- 指定的参数已超出有效值的范围。 参数名: site
“/”应用程序中的服务器错误. 指定的参数已超出有效值的范围.参数名: site 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的 ...
- 常用 Git 命令清单【转--阮一峰】
常用 Git 命令清单 感谢作者 --> 原文链接 我每天使用 Git ,但是很多命令记不住. 一般来说,日常使用只要记住下图6个命令,就可以了.但是熟练使用,恐怕要记住60-100个命令. 下 ...
- Oozie 实战之 Hive
1.编辑job.propertiers nameNode=hdfs://cen-ubuntu.cenzhongman.com:8020 jobTracker=localhost:8032 queueN ...
- 真是shi
降雨量那题,真踏马shi. 调到还有五个RE不调了. 开始以为map可水后来发现一定要二分查找一下. 这种题没啥营养,不过我发现了我ST表一处错误并打了个板子.就这点用处吧. 这几天做题太少了,每天不 ...
- SpringMVC---简单登录例子
所需jar包aopalliance-1.0.jar.commons-logging-1.2.jar.spring-aop-5.0.0.RELEASE.jar.spring-beans-5.0.0.RE ...
- Centos 7.X 安装JDK1.8
一.查看本机jdk版本并卸载原有openjdk 查看 # java -version openjdk version "1.8.0_144" ...
- 《1024伐木累-周末特别篇》-中彩票了,开发APP
本周发布的<1024伐木累>,受到了很多码汪们的好评,博主在这里感谢大家的支持,同时,博主临时起意,增加一期周末对话特别篇,让大家在“满血复活”的时间里,充分感受快乐的味道~ 1.中彩票 ...
- win7重装后恢复grub和ubuntu14
没有光盘和优盘启动盘,可以在win7下安装easybcd,添加一个启动选项为linux grub2,启动后进入ubutnu,执行如下: sudo -i //取得root权限 fdisk -l ...
- 写一个quick sort
#include <stdio.h> #include <stdlib.h> //int a[]={1000,10000,9,10,30,20,50,23,90,100,10} ...
- 剑指Offer - 九度1505 - 两个链表的第一个公共结点
剑指Offer - 九度1505 - 两个链表的第一个公共结点2013-11-24 20:09 题目描述: 输入两个链表,找出它们的第一个公共结点. 输入: 输入可能包含多个测试样例.对于每个测试案例 ...