Codeforces Round #351 (VK Cup 2016 Round 3, Div. 2 Edition)

来源:互联网 发布:linux社区论坛 知乎 编辑:程序博客网 时间:2024/05/17 07:17

链接:http://codeforces.com/contest/673

problemA. Bear and Game:看90分钟电视,有n个有趣点,如果持续15没有看到有趣的点,那么就关电视,问什么时候会关掉电视。

分析:水题。找到第一个跨度大于15的点即可,注意答案最大90。

代码:

#include<map>#include<set>#include<cmath>#include<queue>#include<bitset>#include<math.h>#include<cstdio>#include<vector>#include<string>#include<cstring>#include<iostream>#include<algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int N=500010;const int MAX=1000000100;const int mod=100000000;const int MOD1=1000000007;const int MOD2=1000000009;const double EPS=0.00000001;typedef long long ll;const ll MOD=998244353;const int INF=1000000010;typedef double db;typedef unsigned long long ull;int a[100];int main(){    int i,n,ans=0;    scanf("%d", &n);    for (i=1;i<=n;i++) scanf("%d", &a[i]);    sort(a+1,a+n+1);a[0]=0;    for (i=1;i<=n;i++)    if (a[i]-a[i-1]>15) break ;    else ans=a[i];    printf("%d\n", min(ans+15,90));    return 0;}

problemB. Problems for Round:给定n个人,编号1~n,将这n个人分为两组,给定m个关系,每组关系a,b表示a和b不能在同一组,并且所有关系中较小的在一组,较大的在一组。在较小组中的数要小于任何一个在较大组的数,问有多少种分法。

分析:较小组中存下最大值,较大组中存下最小值,看中间有多少个数是自由的即可,注意关系m==0的情况。

代码:

#include<map>#include<set>#include<cmath>#include<queue>#include<bitset>#include<math.h>#include<cstdio>#include<vector>#include<string>#include<cstring>#include<iostream>#include<algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int N=500010;const int MAX=1000000100;const int mod=100000000;const int MOD1=1000000007;const int MOD2=1000000009;const double EPS=0.00000001;typedef long long ll;const ll MOD=998244353;const int INF=1000000010;typedef double db;typedef unsigned long long ull;int main(){    int i,n,m,mi,mx,x,y;    scanf("%d%d", &n, &m);    mi=0;mx=n+1;    for (i=1;i<=m;i++) {        scanf("%d%d", &x, &y);        if (x>y) swap(x,y);        mi=max(mi,x);mx=min(mx,y);    }    if (mi==0) { printf("%d\n", n-1);return 0; }    if (mx<mi) printf("0\n");    else printf("%d\n", mx-mi);    return 0;}

problemC. Bear and Colors:给定n个数,每个数都在1~n以内,会形成n*(n+1)/2个区间,设x为区间的众数(多个众数取最小的那一个),然后ans[x]++。求统计完所有区间后的ans数组。

分析:固定区间左端点L,然后扩展右端点R,没扩展一次得到一个众数x就ans[x]++即可。

代码:

#include<map>#include<set>#include<cmath>#include<queue>#include<bitset>#include<math.h>#include<cstdio>#include<vector>#include<string>#include<cstring>#include<iostream>#include<algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int N=5010;const int MAX=1000000100;const int mod=100000000;const int MOD1=1000000007;const int MOD2=1000000009;const double EPS=0.00000001;typedef long long ll;const ll MOD=998244353;const int INF=1000000010;typedef double db;typedef unsigned long long ull;int a[N],ans[N],num[N];int main(){    int i,j,n,g,co;    scanf("%d", &n);    for (i=1;i<=n;i++) scanf("%d", &a[i]);    for (i=1;i<=n;i++) {        g=0;co=0;        for (j=i;j<=n;j++) {            num[a[j]]++;            if (num[a[j]]>g) { g=num[a[j]];co=a[j]; }            if (num[a[j]]==g&&a[j]<co) { g=num[a[j]];co=a[j]; }            ans[co]++;        }        for (j=i;j<=n;j++) num[a[j]]--;    }    for (i=1;i<=n;i++) printf("%d ", ans[i]);    printf("\n");    return 0;}

problemD. Bear and Two Paths:给定点数n和k,a,b,c,d。表示要构造出两条长度为n的链v1-v2-...-vn,u1-u2-...-un。v和u都是n的一个排列,表示路径中点的顺序。其中v1==a&&vn==b和u1==c&&un==d且a-b不能直接用边相连,c-d不能直接用边相连。要求最多只能构造k条边(双向边)。无解输出-1,有解输出v和u。

分析:因为要在k条边以内构造出来,我们能想到应该有最优的构造方法。我们再想想无解的情况首先考虑点的约束:很容易想到n==4是无解的,n>4时都能用一个辅助点达到要求然后只要看边的约束。边的约束:首先我们能想到这两条路径要构出至少2个环且最好将能重复使用的边重复使用。知道这些之后画画图就能想出这个模型:构造一个不属于(a,b,c,d)的点e作为辅助点,构造6条边:a-e,a-c,c-e,b-d,b-e,d-e。然后对于多出的点我们只要将它们连成链然后插入到这6条边中任意一个位置即可。这显然是最优的n>4&&边为n+1。

代码:

#include<map>#include<set>#include<cmath>#include<queue>#include<bitset>#include<math.h>#include<cstdio>#include<vector>#include<string>#include<cstring>#include<iostream>#include<algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int N=500010;const int MAX=1000000100;const int mod=100000000;const int MOD1=1000000007;const int MOD2=1000000009;const double EPS=0.00000001;typedef long long ll;const ll MOD=998244353;const int INF=1000000010;typedef double db;typedef unsigned long long ull;int p[1010];int main(){    int a,b,c,d,e,i,n,k;    scanf("%d%d", &n, &k);    scanf("%d%d%d%d", &a, &b, &c, &d);    memset(p,0,sizeof(p));    p[a]=p[b]=p[c]=p[d]=1;    for (i=1;i<=n;i++)    if (!p[i]) { e=i;p[i]=1;break ; }    if (n<5||k<n+1) printf("-1\n");    else {        printf("%d ", a);        for (i=1;i<=n;i++)        if (!p[i]) printf("%d ", i);        printf("%d %d %d %d\n", c, e, d, b);        printf("%d ", c);        for (i=n;i;i--)        if (!p[i]) printf("%d ", i);        printf("%d %d %d %d\n", a, e, b, d);    }    return 0;}

problemE. Levels and Regions:给定n个数t[1]~t[n],给定组数k,将这n个数分为k组,然后求一个期望。规则:1:同一组的元素是连续的,且组不能为空。2:每次找到第一个组(有元素未被杀死),设最小的未死元素为X,不存在则结束游戏。3:对于选定的组G和元素X,将G中杀死的元素i放t[i]个小球到抽奖箱,放t[X]个小球到抽奖箱,然后等概率的抽一个小球,这个操作花费1小时,抽到的小球代表的元素被杀死(如果是已经被杀死就跳过)。要你进行分组,使得所有元素都被杀死需要花费的时间的期望最小。

分析:首先因为同一组只能是连续的元素,我们就要会算连续的[l,r]成为一组是全部被杀死的期望时间,最基础的期望问题,设期望为F[l,r],那么会有F[l,r]=sigma(sum[i]/t[i]-sum[l-1]/t[i]),{l<=i<=r},那么我们就能设dp[i][j]表示将前j个元素分为i个组花费的最小期望。那么状态转移方程式为:dp[i][j]=min(dp[i][k]+F[k,j]),我们设Si=sigma(1<=j<=i)t[j],Qi=sigma(1<=j<=i)Sj/tj,Ri=sigma(1<=j<=i)1/tj。然后我们将dp[i][j]中的F[k,j]用这些表达式替换能得到:dp[i][j]=min(dp[i][k]-Qk+Sk*Rk-Sk*Rj+Qj),这里很明显的斜率优化了。维护一个下凸包就能在O(1)的时间中转移状态啦。O(n*k)。

代码:

#include<map>#include<set>#include<cmath>#include<queue>#include<bitset>#include<math.h>#include<cstdio>#include<vector>#include<string>#include<cstring>#include<iostream>#include<algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int N=1000010;const int MAX=151;const int mod=100000000;const int MOD1=100000007;const int MOD2=100000009;const double EPS=0.00000001;typedef long long ll;const ll MOD=1000000000;const ll INF=1000000000010;typedef double db;typedef long double ldb;typedef unsigned long long ull;ll hea,top,t[N];ldb dx[N],dy[N],dp[2][N],sum[N],sump[N],sumq[N];int cala(ldb x,ldb y,ldb x1,ldb y1,ldb x2,ldb y2) {    return (y2-y1)*(x1-x)>=(y1-y)*(x2-x1);}void add(ldb x,ldb y) {    if (top-hea<1) { top++;dx[top]=x;dy[top]=y;return ; }    while (top-hea>0&&cala(x,y,dx[top],dy[top],dx[top-1],dy[top-1])) top--;    top++;dx[top]=x;dy[top]=y;}int main(){    int i,j,n,k,now,pre;    scanf("%d%d", &n, &k);    for (i=1;i<=n;i++) scanf("%I64d", &t[i]);    t[0]=0ll;sum[0]=sump[0]=sumq[0]=0.0;    for (i=1;i<=n;i++) {        sum[i]=sum[i-1]+1.0*t[i];        sumq[i]=sumq[i-1]+1.0/t[i];        sump[i]=sump[i-1]+sum[i]*1.0/t[i];    }    now=pre=0;    for (i=0;i<=n;i++) dp[now][i]=sump[i];    for (i=2;i<=k;i++) {        pre=now;now^=1;hea=1;top=0;        for (j=i;j<=n;j++) {            add(sum[j-1],sum[j-1]*sumq[j-1]-sump[j-1]+dp[pre][j-1]);            while (top-hea>0&&sumq[j]*(dx[hea]-dx[hea+1])<=dy[hea]-dy[hea+1]) hea++;            dp[now][j]=sump[j]-dx[hea]*sumq[j]+dy[hea];        }    }    printf("%.15f\n", (db)dp[now][n]);    return 0;}


1 0
原创粉丝点击