TopCoder 603 div1 & div2
div2
250pts MiddleCode
题意:s串长度为奇数时,将中间字符取掉并添加到t末尾;长度为偶数时,将中间两个较小的字符取掉并添加到末尾。
分析:直接做,学习了一下substr(s, pos, len)返回s中从pos开始的长度为len的字串。
代码:
class MiddleCode {
public:
void Remove(string &s, int pos) {
int len = s.size();
string t = "";
if(pos < || pos >= len) return;
for(int i = ; i < len; i++)
if(i != pos) t += s[i];
s = t;
}
string encode(string s) {
int n = s.size(), m = n;
string ans = "";
for(int i = ; i < n; i++) {
if((n-i)&) {
ans += s[(n-i)/];
Remove(s, (n-i)/);
} else {
if(s[(n-i)/] < s[(n-i)/-]) {
ans += s[(n-i)/];
Remove(s, (n-i)/);
} else {
ans += s[(n-i)/-];
Remove(s, (n-i)/-);
}
}
}
return ans;
}
};
500pts SplitIntoPairs
题意:将N个数(偶数)分成N/2组,使得两个数的乘积>=X的组数尽量多,X < 0。
分析:X < 0,所以只有当每组的两个数A,B一正一负时才有可能比X小,将N个数分成负数和非负数两组,如果负数有偶数个,那么结果就是N/2组,
因为负数,正数可以分别两两配对。当为奇数的时候,负数和正数两两配对正好剩下一个,且绝对值应该尽量小,判断两数之积和X的关系即可。
代码:
class SplitIntoPairs {
public:
int makepairs(vector <int> A, int X) {
// int n = sz(A);
sort(A.begin(), A.end());
vector<int> B, C;
for(int i = ; i < sz(A); i++){
if(A[i] >= ) B.pb(A[i]);
else C.pb(A[i]);
}
int n = sz(B), m = sz(C);
if(n% == ) return (n+m)/;
return (n+m)/-(1LL*C[m-]*B[] < X);
}
};
950pts GraphWalkWithProbabilities
题意:从一点出发,每一轮选择任意可达的点,该点有win[i], lose[i], 1-win[i]-lose[i]三个概率, 表示到达该点赢,输,继续的概率,从Start出发,
按照最优的走法,最后赢d的概率。
分析:从某一点x出发能够赢得概率和转移到相邻的点y,然后赢的概率有关,但是图中可能存在环,因此采用记忆化搜索的话,
会存在相互依赖关系构成环的情况,转移到一个点y要能够继续进行的话概率为-win[y]-lose[y],那么可以设从y出发,最多进行steps轮,最后能够赢得概率。
这样转移dp[node][steps] = max{ win[to] + (1-win[to]-lose[to]) * dp[to][steps-1] };
steps上界设为3000左右即可,因为1-win[to]-lose[to]最大0.99, 最多3000轮,最终赢得概率应该是能满足题目精度要求的。
代码:
const int maxn = + ;
double dp[][maxn]; class GraphWalkWithProbabilities {
public:
vector<int> win, lose;
vector<int> g[]; double dfs(int node, int steps) {
double &res = dp[node][steps];
if(!(res < )) return res;
res = ;
for(int to: g[node])
res = max(res, win[to]/100.0 + (-win[to]-lose[to])/100.0*dfs(to, steps-));
return res;
}
double findprob(vector <string> graph, vector <int> winprob, vector <int> loseprob, int Start) {
for(int i = ; i < ; i++) for(int j = ; j < maxn; j++)
dp[i][j] = -1.0;
// bug(1)
for(int i = ; i < ; i++) dp[i][] = 0.0;
win = winprob;
lose = loseprob;
// bug(1)
int n = sz(graph);
for(int i = ; i < n; i++){
for(int j = ; j < n; j++)
if(graph[i][j] == '')
g[i].pb(j);
}
dfs(Start, maxn-);
return dp[Start][maxn-];
} };
div1
250pts MaxMinTreeGame
题意:给定一棵N(2 <= N <= 50)的树,两人轮流进行游戏,每次可以删除一条边,然后选择保留其中一棵子树,直到仅剩下一个结点,游戏结束,每个结点都有一个权值,
A想要使得 最后结果尽量大,B想要使得结果尽量小,两人均按照最优方式进行,A先手,求A最终得到的最大值。
分析:所有度数为1的点的中权值最大值(M)即为结果,首先要证明所能获得的最大值不会超过M,因为N>=2的树中度数为1 的结点至少2个,
所以不论A先手时如何操作,剩下的树中,一定会保留下这些结点中的一个,B操作时选取即可,然后证明A先手能够保留权值最大的结点,这个是显然的。
代码:
const int maxn = ;
int du[maxn]; class MaxMinTreeGame {
public:
int findend(vector <int> edges, vector <int> costs) {
memset(du, , sizeof du);
int n = sz(edges) + ;
for(int i = ; i < sz(edges); i++)
du[i+]++, du[edges[i]]++;
int ans = ;
for(int i = ; i < n; i++)
if(du[i] == )
ans = max(ans, costs[i]);
return ans;
} };
500pts PairsOfStrings
题意:给定字符集合为前k个小写字母,定义字符集合上的长度为n的A,B字符串,若存在定义在集合上的C使得A+C=C+B,那么(A,B)记为一对,
现在问(n,k)能够确定的数目,结果MOD (int)1e9 + 7。
分析:首先应该知道B应该是A旋转后的字符串,定义字符串的最小周期长度,A = d^n/d,表示A由n/d个长度为d字符串(记为s)链接构成,A = s + s + ... s,
且不存在更小的长度为d' < d的字符串s',s'重复n/d'之后能够得到A。这样A旋转操作能够得到的不同字符串就为d。那么对于本题需要知道最小周期长度的为d字符串有多少个(num),
最终结果就是所有的d*num之和。显然d应该是n的因子,可能的情况是k^d种,然后这里会有存在重复的情况,例如n = 8, d = 4时,结果k^4中,会包含d = 2中情况,
s = aaaa,A = s+s = aaaaaaaa,显然A可以看做周期长度更小的s' = aa,A = s' + s' + s' + s',所以要把d的因子d'所对应的情况排除。n <= (int)1e9,因子最多1300+个,最后复杂度应该是
O(1300*1300)。
代码:
const int M = ; class PairsOfStrings {
public:
int num[];
int powmod(LL a, LL b, LL c) {
LL res = ;
while(b) {
if(b&) res = res*a%c;
a = a*a%c;
b >>= ;
}
return res;
}
void addIt(int &x, int y) {
x = (x+y)%M;
if(x < ) x += M;
}
void getDivisors(int n, vector<int> &div) {
div.clear();
int m = (int)sqrt(n+.);
for(int i = ; i <= m; i++)
if(n%i == ) {
div.pb(i);
if(n/i != i)
div.pb(n/i);
}
sort(div.begin(), div.end());
}
vector<int> div;
int getNumber(int n, int k) { getDivisors(n, div);
int ans = ;
for(int i = ; i < sz(div); i++) {
int x = div[i];
num[i] = powmod(k, x, M);
for(int j = ; j < i; j++) {
int y = div[j];
if(x%y == ) {
addIt(num[i], -num[j]);
}
}
addIt(ans, 1LL*num[i]*x%M);
}
return ans;
} };
1000pts SumOfArrays
题意:A,B两个数组长度 n <= 100000,A[i],B[i] < 100000,将A,B中的数排列后,使得C[i] = A[i]+B[i]使得C[i]中出现过的数Y出现次数最大。
分析:又是FFT的应用,做法很奇特!分别统计A[i]和B[i]中数出线次数即cntA[A[i]],cntB[B[i]],然后考虑
解法的关键之处就是这里的转化,考虑min(cntA[p],cntB[q]) >= k,那么C[p+q]为(p,q,k)的组数,针对k分别考虑:
k >= 10,显然cntA[p],cntB[q] >= k的p和去不超过(int)1e4,暴力统计C[p+q]的复杂度不会超过(int)1e8,当然实际复杂度可能更低。
k < 10,
z[] = full of zeros
For p = 0 ... 100000 {
For each q = 0 ... 100000 {
z[p + q] = z[p + q] + (x[p] * y[q])
}
}
for i = 0 ... 200000 {
C[i] = C[i] + z[i]
}
这里和大数的乘法十分相似,设立两个数组x[],y[],当x[p] = cntA[p] >= k,y[q] = cntB[q] >= k,剩下的部分利用FFT求出,z[p+q] += x[p]*y[q],由于FFT复杂度为O(MAX*log(MAX)),9次FFT是能够满足效率要求的。
代码:
const int maxn = (int)2e5 + ;
const int LOW = ; int cntA[maxn], cntB[maxn];
int A[maxn], B[maxn], C[maxn];
bitset<maxn> a, b; struct Complex {
double x, y;
Complex() {}
Complex(double x, double y):x(x), y(y) {}
};
Complex operator + (const Complex &a, const Complex &b) {
Complex c;
c.x = a.x+b.x;
c.y = a.y+b.y;
return c;
}
Complex operator - (const Complex &a, const Complex &b) {
Complex c;
c.x = a.x-b.x;
c.y = a.y-b.y;
return c;
}
Complex operator * (const Complex &a, const Complex &b) {
Complex c;
c.x = a.x*b.x-a.y*b.y;
c.y = a.x*b.y+a.y*b.x;
return c;
} inline void FFT(vector<Complex> &a, bool inverse) {
int n = a.size();
for(int i = , j = ; i < n; i++) {
if(j > i)
swap(a[i], a[j]);
int k = n;
while(j & (k>>=)) j &= ~k;
j |= k;
}
double PI = inverse ? -pi : pi;
for(int step = ; step <= n; step <<= ) {
double alpha = *PI/step;
Complex wn(cos(alpha), sin(alpha));
for(int k = ; k < n; k += step) {
Complex w(, );
for(int Ek = k; Ek < k+step/; Ek++) {
int Ok = Ek + step/;
Complex u = a[Ek]; Complex t = a[Ok]*w;
a[Ok] = u-t;
a[Ek] = u+t;
w = w*wn;
}
}
}
if(inverse)
for(int i = ; i < n; i++)
a[i].x = (a[i].x/n);
}
vector<int> operator * (const bitset<maxn> &v1, const bitset<maxn> &v2) {
int S1 = v1.size(), S2 = v2.size();
int S = ;
while(S < S1+S2) S <<= ;
vector<Complex> a(S), b(S);
for(int i = ; i < S; i++)
a[i].x = a[i].y = b[i].x = b[i].y = 0.0;
for(int i = ; i < S1; i++)
a[i].x = v1[i];
for(int i = ; i < S2; i++)
b[i].x = v2[i];
FFT(a, false);
FFT(b, false);
for(int i = ; i < S; i++)
a[i] = a[i] * b[i];
FFT(a, true);
vector<int> res(maxn, );
for(int i = ; i < maxn; i++)
res[i] = round(a[i].x);
return res;
} class SumOfArrays {
public:
void gen(int A[], vector<int> seed, int n) {
A[] = seed[];
A[] = seed[];
for(int i = ; i < n; i++)
A[i] = (1LL * A[i-] * seed[] + 1LL* A[i-] * seed[] + seed[]) % seed[];
// for(int i = 0; i < n; i++)
// printf("%d ", A[i]);
// puts("");
}
char ans[]; string findbestpair(int n, vector <int> Aseed, vector <int> Bseed) {
gen(A, Aseed, n);
gen(B, Bseed, n);
// memset(cntA, 0, sizeof cntA);
memset(cntB, , sizeof cntB);
memset(C, , sizeof C); for(int i = ; i < n; i++) {
cntA[A[i]]++;
cntB[B[i]]++;
} vector<int> bigA, bigB;
for(int i = ; i < maxn; i++) {
if(cntA[i] >= LOW)
bigA.pb(i);
if(cntB[i] >= LOW)
bigB.pb(i);
} for(int p: bigA) for(int q: bigB) {
C[p+q] += min(cntA[p], cntB[q]) - LOW + ;
}
vector<int> c(maxn);
for(int k = ; k < ; k++) {
a.reset();
b.reset();
for(int i = ; i < maxn; i++) {
if(cntA[i] >= k)
a[i] = ;
if(cntB[i] >= k)
b[i] = ;
} c = a*b;
for(int i = ; i < maxn; i++)
C[i] += c[i];
// for(int i = 1; i <= 4; i++)
// cout << C[i] << ' ';
// cout << endl;
} int X = -, Y = ;
for(int i = ; i < maxn; i++)
if(C[i] >= X) {
X = C[i];
Y = i;
} sprintf(ans, "%d %d", X, Y);
// TL
return ans;
} };
TopCoder 603 div1 & div2的更多相关文章
- TopCoder 649 div1 & div2
最近一场TC,做得是在是烂,不过最后challenge阶段用一个随机数据cha了一个明显错误的代码,最后免于暴跌rating,还涨了一点.TC题目质量还是很高的,非常锻炼思维,拓展做题的视野,老老实实 ...
- 【前行&赛时总结】◇第4站&赛时9◇ CF Round 513 Div1+Div2
◇第4站&赛时9◇ CF Round 513 Div1+Div2 第一次在CF里涨Rating QWQ 深感不易……作blog以记之 ( ̄▽ ̄)" +Codeforces 的门为你打 ...
- Topcoder SRM 603 div1题解
昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点 ...
- Topcoder Srm 673 Div2 1000 BearPermutations2
\(>Topcoder \space Srm \space 673 \space Div2 \space 1000 \space BearPermutations2<\) 题目大意 : 对 ...
- Topcoder Srm 671 Div2 1000 BearDestroysDiv2
\(>Topcoder \space Srm \space 671 \space Div2 \space 1000 \space BearDestroysDiv2<\) 题目大意 : 有一 ...
- 求拓扑排序的数量,例题 topcoder srm 654 div2 500
周赛时遇到的一道比较有意思的题目: Problem Statement There are N rooms in Maki's new house. The rooms are number ...
- Topcoder srm 632 div2
脑洞太大,简单东西就是想复杂,活该一直DIV2; A:水,基本判断A[I]<=A[I-1],ANS++; B:不知道别人怎么做的,我的是100*N*N;没办法想的太多了,忘记是连续的数列 我们枚 ...
- TopCoder SRM500 Div1 250 其他
原文链接https://www.cnblogs.com/zhouzhendong/p/SRM500-250.html SRM500 Div1 250 题意 (看题用了半个小时--) 有 n 个人(编号 ...
- TopCoder SRM500 Div1 500 分治
原文链接https://www.cnblogs.com/zhouzhendong/p/SRM500-500.html SRM500 Div1 500 没想到 double 的精度居然没有爆-- 考虑以 ...
随机推荐
- css style与class之间的区别
问题描述: 网页点击[导出]按钮后,将页面table内容另存成excel文件,却发现无法保存表格样式 分析过程: 1.table表格用class,而不是style.导出时并没有导出class定义 ...
- 一款仿PBA官网首页jQuery焦点图的切换特效
一款仿PBA官网首页jQuery焦点图的切换特效,非常的简单大方, 在对浏览器兼容性的方面做了不少的功夫.IE6也勉强能过去. 还是一款全屏的焦点图切换特效.大气而清新.很适合简介大方的网站. 下图还 ...
- mongodb学习之路1
第一节 MongoDB介绍及下载与安装 引言 MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的.他支持的数据结构非常松散,是类似 json的b ...
- [转]Linux下修改/设置环境变量JAVA_HOME
1. 永久修改,对所有用户有效 # vi /etc/profile //按键盘[Shift + g], 在profile文件最后添加下面的内容: export JAVA_HOME = /home/m ...
- C# 缓存学习第一天
缓存应用目的:缓存主要是为了提高数据的读取速度.因为服务器和应用客户端之间存在着流量的瓶颈,所以读取大容量数据时,使用缓存来直接为客户端服务,可以减少客户端与服务器端的数据交互,从而大大提高程序的性能 ...
- JS模板Handlebars的使用和有效组织
应用背景 我们在做项目时,为了使页面模块高度复用,使用页面模板是必须的,我想大家通常可能会新建MVC的项目,然后在页面中使用Razor引擎,新建Helper模板类,前后台代码的混写,简洁高效,一切 ...
- 数据分析≠Hadoop+NoSQL,不妨先看完善现有技术的10条捷径(分享)
Hadoop让大数据分析走向了大众化,然而它的部署仍需耗费大量的人力和物力.在直奔Hadoop之前,是否已经将现有技术推向极限?这里总结了对Hadoop投资前可以尝试的10个替代方案, ...
- return *this和return this的区别
别跟我说, return *this返回当前对象, return this返回当前对象的地址(指向当前对象的指针). 正确答案为:return *this返回的是当前对象的克隆(当然, 这里仅考虑返回 ...
- oracle 存储过程编辑 卡死
一.可用SYS登录, 二.查锁session_ID查找存储过程OPERATIONDATA_IMP被哪些session锁住而无法编译select * FROM dba_ddl_locks where n ...
- 一致性hash应用到redis
理解分布式存储的本质 有一个经典的实践经验: 数(值)据大了, 什么都是问题! 如果要求128B或更大数值计算, 哪么四则运算会是个大问题! 如果要求128T或更大日志存储, 哪么文件存储会是个大问题 ...