王者荣耀_KEY
来源:互联网 发布:网络层协议有哪些 编辑:程序博客网 时间:2024/04/28 18:01
WZRY
为了排位赛的Cjj神,最近耗尽气力来打WZRY。
Cjj神最近有N局预约的排位赛,其中第i局需要耗时Li的时间。因为浓浓的Gay情,Cjj神不能改变这些排位赛的的顺序。作为一个很有(mei)自制力的人,Cjj神计划用M+1天打完N局,为了能够活着见到第M+2天的太阳,他希望耗时最长的一天最短。
每天最少打一局。
请告诉他这个值是多少,以使他判断他是否能活下来;并且告诉他在总时长最长一天等于这个最小值的情况下有多少种方案,以使他判断他活下来的概率是多少。
输入格式:
第一行两个整数N,M。
接下来N个整数Li。
输出格式:
一行两个数,第一个是总时长最长的一天的最小值,第二个数是方案总数,对10,007取模。
数据范围:
10%:N<=25
30%:N<=300
60%:N<=10000
100%:N<=50000,0<=m< n,m<1000,1<=Li<=1000
这道题有两问,第一问可以很简单地用二分+贪心解决。
但第二问呢?
首先这道题的普通暴力DP是很好想到的,设f[i][j]为第i天,打了j局比赛的方案总数。
很显然f[i][j]=∑f[i-1][k](sum[j]-sum[k]<=ans)
sum为Li的前缀和。
奉上暴力代码:
#include <bits/stdc++.h>#define mod 10007using namespace std;inline char tc(){ static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;}inline int read(){ char c; while(!isdigit(c=tc()));int x=c-'0'; while(isdigit(c=tc()))x=x*10+c-'0'; return x;}int n,m,a[30001],mx,ans,ww,f[1001][30001],sum[30001];int check(int x){ int tot=0,last=x,d=1; for(int i=1;i<=n;i++) if(last>=a[i])last-=a[i]; else d++,last=x-a[i]; return d<=m;}int main(){ n=read(),m=read();m++; for(int i=1;i<=n;i++)a[i]=read(),mx=max(mx,a[i]),ww+=a[i],sum[i]=sum[i-1]+a[i]; int L=mx,R=ww; while(L<=R){ int mid=L+R>>1; if(check(mid))R=mid-1,ans=mid; else L=mid+1; }//二分,第一问 for(int i=1;i<=m;i++){f[i-1][0]=1; for(int j=i;j<=n;j++){ for(int k=i-1;k<j;k++) if(sum[j]-sum[k]<=ans) f[i][j]=(f[i][j]+f[i-1][k])%mod; } } int tot=0; for(int i=1;i<=m;i++)tot=(tot+f[i][n])%mod; printf("%d %d",ans,tot);}
这个O(M*N^2)的效率一定会超时,所以我们要对暴力优化。
仔细看这个暴力,不难发现其实是一个不停枚举j和k边界的过程。
又想到我们知道最大耗时的最小值,那么就可以在已知k便边界的情况下通过预处理求出j边界的值。
设pre[i]表示第i局最远可以由哪一局转移过来。
那么只需枚举k加前缀和维护f数组的值就可以得到O(MN)的算法了。
但通过观察数据可得内存会炸,由于有前缀和维护,只需要每次i做完1次时将f清零即可。
code:
#include <bits/stdc++.h>#define mod 10007#define ll long longusing namespace std;inline char tc(){ static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;}inline int read(){ char c; while(!isdigit(c=tc()));int x=c-'0'; while(isdigit(c=tc()))x=x*10+c-'0'; return x;}int n,m,a[30001],mx,ans,ww,f[30001];int sum[30001],pre[30001],d[30001];int check(int x){ int tot=0,last=x,d=1; for(int i=1;i<=n;i++) if(last>=a[i])last-=a[i]; else d++,last=x-a[i]; return d<=m;}int main(){ n=read(),m=read();m++; for(int i=1;i<=n;i++)a[i]=read(),mx=max(mx,a[i]),ww+=a[i],sum[i]=sum[i-1]+a[i]; int L=mx,R=ww; while(L<=R){ int mid=L+R>>1; if(check(mid))R=mid-1,ans=mid; else L=mid+1; } for(int i=1;i<=n;i++){int sum=0; for(int j=i;j>0;j--){ if(sum+a[j]<=ans)sum+=a[j]; else {pre[i]=j;break;} } }//预处理pre for(int i=0;i<=n;i++)d[i]=1; int tot=0; for(int i=1;i<=m;i++){ for(int j=i;j<=n;j++){ if(pre[j]>0)f[j]=(f[j]+d[j-1]-d[pre[j]-1])%mod; else f[j]=(f[j]+d[j-1])%mod; }d[0]=0; tot=(tot+f[n])%mod; for(int j=1;j<=n;j++)d[j]=(d[j-1]+f[j])%mod,f[j]=0;//维护,清零 } tot=((tot+mod)%mod+mod)%mod; printf("%d %d",ans,tot);}
阅读全文
0 0
- 王者荣耀_KEY
- 王者荣耀
- 王者荣耀
- 王者荣耀提取攻略
- 王者的荣耀--Monza后记
- 《王者荣耀》手游感想
- 玩-王者荣耀-英雄缺点
- vue2.0-王者荣耀助手
- 【王者荣耀】入门战斗经验
- 如何戒掉王者荣耀
- “王者荣耀”中的常用英语
- 论王者荣耀英雄花木兰
- 数据分析软件解读王者荣耀一年的“王者”成绩单
- 报名|如何在《王者荣耀》里成为最强王者?
- 王者荣耀游戏英文及翻译
- 王者荣耀的帧同步机智
- 王者荣耀 是什么语言编写的
- 王者荣耀签到系统策划案
- 笔记
- 2017/9/21工作总结
- 数据库导入导出数据以及字段类型为timestamp时的设值问题
- HashMap和HashTable的区别和联系
- 网络编程
- 王者荣耀_KEY
- doppia调试之旅
- 微信小程序音频播放
- 判断ResultSet结果集是否为空
- 训练3+ A-Watching TV
- C语言小知识
- HorizontalScrollView横向滑动静态方法
- 闭锁CountDownLatch与栅栏CyclicBarrier
- ClusterControl