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的更多相关文章

  1. TopCoder 649 div1 & div2

    最近一场TC,做得是在是烂,不过最后challenge阶段用一个随机数据cha了一个明显错误的代码,最后免于暴跌rating,还涨了一点.TC题目质量还是很高的,非常锻炼思维,拓展做题的视野,老老实实 ...

  2. 【前行&赛时总结】◇第4站&赛时9◇ CF Round 513 Div1+Div2

    ◇第4站&赛时9◇ CF Round 513 Div1+Div2 第一次在CF里涨Rating QWQ 深感不易……作blog以记之 ( ̄▽ ̄)" +Codeforces 的门为你打 ...

  3. Topcoder SRM 603 div1题解

    昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点 ...

  4. Topcoder Srm 673 Div2 1000 BearPermutations2

    \(>Topcoder \space Srm \space 673 \space Div2 \space 1000 \space BearPermutations2<\) 题目大意 : 对 ...

  5. Topcoder Srm 671 Div2 1000 BearDestroysDiv2

    \(>Topcoder \space Srm \space 671 \space Div2 \space 1000 \space BearDestroysDiv2<\) 题目大意 : 有一 ...

  6. 求拓扑排序的数量,例题 topcoder srm 654 div2 500

    周赛时遇到的一道比较有意思的题目: Problem Statement      There are N rooms in Maki's new house. The rooms are number ...

  7. Topcoder srm 632 div2

    脑洞太大,简单东西就是想复杂,活该一直DIV2; A:水,基本判断A[I]<=A[I-1],ANS++; B:不知道别人怎么做的,我的是100*N*N;没办法想的太多了,忘记是连续的数列 我们枚 ...

  8. TopCoder SRM500 Div1 250 其他

    原文链接https://www.cnblogs.com/zhouzhendong/p/SRM500-250.html SRM500 Div1 250 题意 (看题用了半个小时--) 有 n 个人(编号 ...

  9. TopCoder SRM500 Div1 500 分治

    原文链接https://www.cnblogs.com/zhouzhendong/p/SRM500-500.html SRM500 Div1 500 没想到 double 的精度居然没有爆-- 考虑以 ...

随机推荐

  1. JavaScript ==和===

    == :  值等 === :恒等(引用等) ref: http://blog.csdn.net/wang171838/article/details/8554305 JavaScript支持“=”.“ ...

  2. php异步调试和线上调试网站程序的方法

    当碰到一个网站需要不间断运行,但又需要调试该网站的程序错误的时候,该如何办呢?是靠经验一点点猜测,还是直接打印错误信息让其在页面输出? 下面分享一种方法同时满足这两种条件,既方便网站程序错误调试,又不 ...

  3. haproxy 安装与配置文件详解

    本文主要阐述haproxy的安装配置详解,对于它的概念,作用,功能,和其它LB软件的区别,优点,缺点等不再进行说明. 一. haproxy 的安装配置 # cat /etc/redhat-releas ...

  4. 简单的Datatable转List,Json

    这里用到了Newtonsoft.Json,下载地址:http://json.codeplex.com/ 1.根据不同的Model转为对应的List public static List<Mode ...

  5. 【转】常用插件和mvn test命令

    自定义构建Maven项目,需要包括额外的插件或者配置已存在的插件参数. 1. maven-compiler-plugin 指定JDK版本和编码方式 compiler插件能解决2个问题: 第一: mav ...

  6. 第六周 N题

    Description As Harry Potter series is over, Harry has no job. Since he wants to make quick money, (h ...

  7. Jquery each 的跳出 break continue

    在Jquery each 中 break 是用 return false; continue 是用 return true;

  8. API网关

    API网关 最开始只是想找个API网关防止API被恶意请求,找了一圈发现基于Nginx的OpenResty(Lua语言)扩展模块Orange挺好(也找了Kong,但是感觉复杂了点没用),还偷懒用Vag ...

  9. Ubuntu多系统安装注意事项

    1. 安装 选择分区时一定要全设置成逻辑分区,不能是主分区! 2.多系统引导向修复 利用LiveCD制作U盘启动进入Ubuntu系统,若挂载点为: /dev/sda9             swap ...

  10. [转载+原创]Emgu CV on C# (三) —— Emgu CV on 均衡化

    本文简要描述了均衡化原理及数学实现等理论问题,最终利用emgucv实现图像的灰度均衡. 直方图的均衡化,这是图像增强的常用方法. 一.均衡化原理及数学实现(转载) 均衡化原理及数学实现可重点参看——& ...