codeforces contest 352
2016-12-02 14:24
288 查看
http://codeforces.com/contest/352
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C 351A Jeff
and Rounding
题意:给出2n个数,将其中n个向下取整,剩下n个向上取整,要使操作之后的数之和和操作之前的数之和的差值最小,问最小差值。
题解:很明显只和小数部分有关,那么我们把有小数部分的数的小数部分提取出来。排序,选择前k小向下取整,维护一个最小的ans。
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
D 351B Jeff
and Furik
题意:
题解:其实我是猜的(刷完概率dp专题再来写题解)
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
E 351C Jeff
and Brackets
题意:要构造一个n*m的合法括号序列。如果位置i是左括号,那么它的值为a[i%n],否则它的值为b[i%n]。求最小的值。
题解:
1、定义bal:左括号数量减去右括号数量。
2、把待求序列ANS拆分成m段大小为n的序列。可以证明ANS的 前缀bal ≤ n(证明下面写)。
3、我们取出第X段。
d[k][i][j](d[0~n][1~n][0~n])表示前X-1段序列的 前缀bal = k ,前X-1段序列加上第X段序列的前i个字符的 前缀bal = j 。
d[k][0][k]=0
if(j-1≥0) d[k][i][j]=min(d[k][i][j],d[k][i-1][j-1]+a[i]);
if(j+1≤n) d[k][i][j]=min(d[k][i][j],d[k][i-1][j+1]+b[i]);
4、因此我们可以得出一个矩阵M。
M[i][j]表示前X-1段序列的前缀bal=i,如果要让前X段序列的前缀bal=j,需要花费的代价。
5、很容易知道第0段的前缀bal是0,现在我们要求的是:让前m段的前缀bal=0花费的最小代价。
这个可以用矩阵快速幂优化。(比较不好描述,可以看矩阵快速幂部分的代码)
最后的答案就是powmul(M,k).mat[0][0]
证明ANS的 前缀bal ≤ n:
取出一段前缀bal大于n(假设它的值是res)的序列A,那么它长度必定大于n,并且在它之后必定有一段序列B的bal等于-res,序列B的长度也大于n。
在维护序列的合法性的情况下,我们必定可以把A中的一部分和B中的一部分交换,使得res的值下降。重复这个步骤直到ANS的前缀bal≤n。得证。
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C 351A Jeff
and Rounding
题意:给出2n个数,将其中n个向下取整,剩下n个向上取整,要使操作之后的数之和和操作之前的数之和的差值最小,问最小差值。
题解:很明显只和小数部分有关,那么我们把有小数部分的数的小数部分提取出来。排序,选择前k小向下取整,维护一个最小的ans。
#include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cstdio> #include <string> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; typedef long long ll; #define de(x) cout << #x << "=" << x << endl const int N=4005; double a ; int main() { int n; while(~scanf("%d",&n)) { int m=0; double x,det=0; for(int i=1;i<=2*n;++i) { cin>>x; int xx=x; if(x-(double)xx>0.0001) { a[++m]=x-(double)xx; det+=x-(double)xx;//加上实数部分 } } sort(a+1,a+1+m); double ans=fabs(det-(m-max(0,m-n))); int tt=min(m,n); for(int i=max(0,m-n)+1;i<=tt;++i) {//i个向下取整的 double t=fabs(det-(m-i)); ans=fmin(ans,t); } printf("%.3lf\n",ans); } return 0; }
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
D 351B Jeff
and Furik
题意:
题解:其实我是猜的(刷完概率dp专题再来写题解)
#include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cstdio> #include <string> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; typedef long long ll; #define de(x) cout << #x << "=" << x << endl const int N=3005; int a ; int main() { int n; while(~scanf("%d",&n)) { int cnt=0; for(int i=1;i<=n;++i) { scanf("%d",&a[i]); for(int j=1;j<i;++j) { if(a[j]>a[i]) ++cnt; } } if(cnt==0) { puts("0.000000"); } else if(cnt&1) { printf("%d.000000\n",2*cnt-1); } else { printf("%d.000000\n",2*cnt); } } return 0; }
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
E 351C Jeff
and Brackets
题意:要构造一个n*m的合法括号序列。如果位置i是左括号,那么它的值为a[i%n],否则它的值为b[i%n]。求最小的值。
题解:
1、定义bal:左括号数量减去右括号数量。
2、把待求序列ANS拆分成m段大小为n的序列。可以证明ANS的 前缀bal ≤ n(证明下面写)。
3、我们取出第X段。
d[k][i][j](d[0~n][1~n][0~n])表示前X-1段序列的 前缀bal = k ,前X-1段序列加上第X段序列的前i个字符的 前缀bal = j 。
d[k][0][k]=0
if(j-1≥0) d[k][i][j]=min(d[k][i][j],d[k][i-1][j-1]+a[i]);
if(j+1≤n) d[k][i][j]=min(d[k][i][j],d[k][i-1][j+1]+b[i]);
4、因此我们可以得出一个矩阵M。
M[i][j]表示前X-1段序列的前缀bal=i,如果要让前X段序列的前缀bal=j,需要花费的代价。
5、很容易知道第0段的前缀bal是0,现在我们要求的是:让前m段的前缀bal=0花费的最小代价。
这个可以用矩阵快速幂优化。(比较不好描述,可以看矩阵快速幂部分的代码)
最后的答案就是powmul(M,k).mat[0][0]
证明ANS的 前缀bal ≤ n:
取出一段前缀bal大于n(假设它的值是res)的序列A,那么它长度必定大于n,并且在它之后必定有一段序列B的bal等于-res,序列B的长度也大于n。
在维护序列的合法性的情况下,我们必定可以把A中的一部分和B中的一部分交换,使得res的值下降。重复这个步骤直到ANS的前缀bal≤n。得证。
#include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cstdio> #include <string> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; typedef long long ll; #define de(x) cout << #x << "=" << x << endl const int N=25; ll a ,b ,d ; int n,m; struct Mat { ll mat ; Mat() {memset(mat,0x3f,sizeof(mat));} Mat operator * (Mat B) { Mat C; for(int i=0;i<=n;++i) { for(int j=0;j<=n;++j) { for(int k=0;k<=n;++k) { C.mat[i][j]=min(C.mat[i][j],mat[i][k]+B.mat[k][j]); } } } return C; } }; Mat powmul(Mat A,int k) { Mat B; for(int i=0;i<=n;++i) B.mat[i][i]=0; while(k) { if(k&1) B=B*A; A=A*A; k>>=1; } return B; } Mat M; int main() { while(~scanf("%d%d",&n,&m)) { for(int i=1;i<=n;++i) scanf("%I64d",&a[i]); for(int i=1;i<=n;++i) scanf("%I64d",&b[i]); memset(d,0x3f,sizeof(d)); for(int k=0;k<=n;++k) { d[k][0][k]=0; for(int i=1;i<=n;++i) { for(int j=0;j<=n;++j) { if(j-1>=0) d[k][i][j]=min(d[k][i][j],d[k][i-1][j-1]+a[i]); if(j+1<=n) d[k][i][j]=min(d[k][i][j],d[k][i-1][j+1]+b[i]); } } } for(int i=0;i<=n;++i) { for(int j=0;j<=n;++j) { M.mat[i][j]=d[i] [j]; } } printf("%I64d\n",powmul(M,m).mat[0][0]); } return 0; }
相关文章推荐
- Codeforces 501A:Contest(水题)
- Codeforces-20152016-northwestern-european-regional-contest-nwerc-A题
- Codeforces 656 B. Scrambled(April Fools Day Contest 2016)
- 【Codeforces】2015-2016 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2015) A Adjoin the Netwo
- Codeforces 2015-2016 ACM-ICPC, NEERC, Southern Subregional Contest A题 (String模拟)
- CodeForces - 681A A Good Contest
- codeforces contest 357
- Codeforces contest 295 recordings
- codeforces 352 div 2 C.Recycling Bottles 贪心
- Codeforces-Round-#357-(Div.-2)-A-Good-Contest
- codeforces contest 327
- CodeForces 589J ——2015-2016 ACM-ICPC, NEERC, Southern Subregional Contest
- CodeForces 377B---Preparing for the Contest(二分+贪心)
- 【codeforces】2014-2015 ACM-ICPC, Central Europe Regional Contest (CERC 14) F Vocabulary【dp】
- Codeforces 2016 ACM Amman Collegiate Programming Contest B. The Little Match Girl(贪心)
- codeforces contest 855 problem C(树形DP)
- Codeforces 2016 ACM Amman Collegiate Programming Contest B. The Little Match Girl(贪心)
- codeforces contest 869 problem C(组合数)
- codeforces contest 13 problem E(分块)
- CodeForces 501A Contest(水题,感觉BUG)