NOIP第二次模拟赛 stage1【划分数列(seq.pas/c/cpp)

7划分数列(seq.pas/c/cpp)

【题目描述】

给你一个有n个元素的数列,要求把它划分成k段,使每段元素和的最大值最小

【输入格式】

第一行两个正整数n,k

第二行为此数列ai

【输出格式】

一行一个数,为题目所求答案

【样例输入】

5 2

2 1 3 4 5

【样例输出】

9

【数据规模】

30%数据 n <= 30, k <= 10

100%数据 n <= 100000, k <= n, ai <= 10^9

150%数据 n <= 100000, k <= n, |ai| <= 10^9(附:这50分超越了noip难度,大家可以无视)

【时限】

1s

刚拿到的时候没看数据觉得是动归,QAQ看了数据觉得应该要有优化,二分或者贪心吧。

然而考试的时候并没有做出来(╯‵□′)╯︵┻━┻后来看到大牛的题解,写得很好,贴在这里

http://blog.sina.com.cn/s/blog_9aa2786a01018ksx.html 量子压缩的新浪博客

标程果然二分,当然这道题最大的难点不在二分数据而在于判断是否能够划分这个数据;

下面代码中有足够的注释,文末贴出判断过程

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int n,k;
 6 long long sum,maxn;
 7 long long num[100001];
 8 void read()
 9 {
10     scanf("%d%d",&n,&k);
11     for(int i=1;i<=n;i++)
12     {
13         scanf("%lld",&num[i]);
14         sum+=num[i];//记录总和;
15         maxn=max(maxn,num[i]);//记录最大值;
16     }
17 }
18 bool judge(int x)//判断能否划分这个数
19 {
20     long long temp=0;
21     int pos=0;//记录划分的段数;
22     for(int i=1;i<=n;i++)
23     {
24         temp+=num[i];
25         if(temp<=x&&(temp+num[i+1])>x)//在i这个位置可以划分;
26         {
27             temp=0;//重置
28             pos++;//段数加一;
29         }
30         if(pos==k&&i<n) return 0;//如果划分的段数将要超过k,那么不能划分为k段,即这个数不能划分;
31     }
32     return 1;//否则能划分;
33 }
34 void work()//二分
35 {
36     long long r=sum;
37     long long l=maxn;
38     long long m;
39     while(l<=r)
40     {
41         long long mid=(l+r)/2;
42         if(judge(mid))//若这个数可以划分,向左寻找比它小的下一个可以划分的数;
43         {
44             r=mid-1;
45             m=mid;//记录这个可以划分的数;
46         }
47         else l=mid+1;//若不能划分,向右寻找比它大的下一个可以划分的数;
48     }
49     printf("%lld",m);
50 }
51 int main()
52 {
53     freopen("seq.in","r",stdin);
54     freopen("seq.out","w",stdout);
55     read();
56     work();
57     return 0;
58 }

下面的判断过程也许有点冗长(三个图),代码看懂的同学没有必要往下翻啦。

—!@¥~!#@W~……%——心情复杂的分割线lヾ(?`Д´?)——$—%……¥%¥#¥@#@@@!—

以样例为例,

第一次二分:l=5,r=15,mid=10;

judge

10可以划分,于是r=mid-1=9;

mid=(9+5)/2=7;

7不能划分(划分需要3段),所以l=8,mid=7,后面重复上述过程;

直到mid=9,

终于可以划分了(っ*´Д`)っ,此时m=9,r=8,l=8+1=9,因为l>r,所以二分完毕,打印答案。

前面十个数据没有负数,最后五个有_(:з」∠)_,现在还写不出来所以只得了100分没有AC这道题。

应该会有后续更新【╰(*°▽°*)╯

时间: 2024-10-12 13:01:01

NOIP第二次模拟赛 stage1【划分数列(seq.pas/c/cpp)的相关文章

NOIP 2012 提高组第二试模拟赛 Solution

第一题 题意 数据范围 Solution 三分求下凹函数最值 1 #include <cstdio> 2 #include <queue> 3 #include <iostream> 4 using namespace std; 5 inline void read(int &k) 6 { 7 k=0;int f=1;char c=getchar(); 8 while (c<'0'||c>'9')c=='-'&&(f=-1),c=ge

2014-10-18 noip提高组模拟赛(codecomb)[未填]

> <看了一下觉得挺难的...除了T2 T1只想到了找环,> <倍增的思想没有学过,所以看题解看得雨里雾里的(最近真的打算学一下!) T2贪心..很容易看出的 T3感觉题目没有怎么看懂...> <正解居然是树形dp 果然不太会 T4蒟蒻> <我连最小子矩阵都不会求T_T其他更不用说了 虽然没有参加比赛,但感觉自己到不了200(hzwer说没有200应该去参加普及组QAQ) 题目出的挺好的,觉得noip极有可能出现T1T2T3,所以在此mark 而且T1以为是

1.28 noip t1难度模拟赛

1 0pts 2 10pts 3 100pts 本想装个逼,从后面开始做,确实t3第一个AC,获得了紫色high light,BUT,第二题自己造的极端数据都过了,结果上讲台看,0分!!怎么可能?!检查了一下精度问题,没毛病啊,在最后两分钟发现我把题读错了--我以为必须要是升序的数列--被坑惨了,两分钟改了一下,得了10pts呵呵.t1没时间调了,死循环 t1迷宫 注意用dp做啊!dfs会爆,bfs懒得写-- #include <bits/stdc++.h> #define rep(i,a,b

10-18 noip提高组模拟赛(codecomb)T2贪心

T2:找min:一直找最小的那个,直到a[i]-x+1小于0,就找次小的,以此类推: 求max,也是一样的,一直到最大的那个,直到次大的比之前最大的大,就找次大的: 这个模拟,可以用上priority_queue: #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <queue> using namespace std; c

[模拟赛] T2 不等数列

Description 将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入">"和"<".问在所有排列中,有多少个排列恰好有k个"<".答案对2015取模. 注:1~n的排列指的是1~n这n个数各出现且仅出现一次的数列. Input 第一行2个整数n,k. Output 一个整数表示答案. Range 对于30%的数据:n <= 10 对于100%的数据:k < n <= 1000 Solutio

模拟赛 Chino的数列

矩阵加速递推 n的范围比较小,k的范围很大,我们可以考虑从n入手. 1.首先我们知道任何矩阵*单位矩阵都不会改变. 所以对于交换操作,我们可以造出一个这样的矩阵: 除了第s.m行,其他每一行都是f[i][i]=1; 第s行:f[s][m]=1;第m行:f[m][s]=1; 这样我们就完成了交换操作. 2.对于左移操作,我们也可以造出一个这样的矩阵: 除了第n行,其他每一行都是f[i][i+1]=1; 第n行:f[n][1]=1; 3.我们的初始矩阵f[i][1]=a[i]; 因为矩阵符合结合律,

【csp模拟赛1】不服来战 (challenge.cpp)

[题目描述] 最近小 Z 和他的朋友都迷上了一款手机游戏:不服来战. 游戏的设定十分简单,在游戏开始时,会给出一排共 N 个灯,有的灯是开着 的有的是关着的,每个灯都有一个分数.而玩家可以进行任意次操作,每次操作 改变连续 K 盏灯的开关状态.尽管机智如小 Z 也总是没法得到最高分,没法把他 的朋友 PK 下来.于是他来向你请教,希望知道在不同情况下,最高分分别是多 少. [输入格式] 第一行,一个正整数 T,表示测试数据组数. 对于每组测试数据: 首先是一行两个正整数 N,K,意义如题目所述.

【2018.11.22】ctsc2018(模拟赛!)

太蠢了……$noip$ 后第一次模拟赛竟然是这样的……完全就是打击自信 / 降智…… 1. 假面 一道神仙概率 $dp$!第一次写…… 拿到题就发现血量 $m_i$ 的上限只有 $100$! 然后 $0$ 操作就可以用 $rate(i,j)$ 动态维护第 $i$ 个人血量为 $j$ 的概率啦. $1$ 操作比较麻烦(但是它故意弄得很少). 设 $live_i$ 和 $dead_i$ 分别为 $1$ 操作范围内的第 $i$ 个人活着和死了的概率,$g_{i,j}$ 是除 $i$ 以外有 $j$ 个

NOIP模拟赛 数列(seq)

Problem 2 数列(seq.cpp/c/pas) [题目描述] a[1]=a[2]=a[3]=1 a[x]=a[x-3]+a[x-1]  (x>3) 求a数列的第n项对1000000007(10^9+7)取余的值. [输入格式] 第一行一个整数T,表示询问个数. 以下T行,每行一个正整数n. [输出格式] 每行输出一个非负整数表示答案. [样例输入] 3 6 8 10 [样例输出] 4 9 19 [数据范围] 对于30%的数据 n<=100: 对于60%的数据 n<=2*10^7: