noip2019…counting down three weeks

纪中day2

10.30纪中B组notes

  • 小麦亩产一千八(kela)-_-
  • 休息(rest)
  • 军训(training)

题目来源:
NOIP2013 Day1
命题学校:衡阳市第八中学
命题人:ZY,LMZ

依旧是蒟蒻的悲惨一天o(╥﹏╥)o

keys & notes 部分来源于纪中题解

T1 小麦亩产一千八(kela)

强烈谴责此类“放卫星”行为!!

题目描述

jzoj 3461 纪中链接(可能失效)

“有了金坷垃,肥料一袋能顶两袋撒,小麦亩产一千八,吸收两米下的氮磷钾……”,
话说HYSBZ(Hengyang School for Boys & Zy)学识渊博孩纸们一讲到粮食,
都会想起印度那个著名的故事:国王要在第一个格子里放入一粒小麦,
接下来的格子放入前面一个格子的两倍的小麦。
这样所需小麦总数是巨大的,哪是不用金坷垃就能完成的任务?
不过为了减轻国王的任务,那个下棋获胜的宰相换了一个要求:
“我只需要你在棋盘外放一粒小麦,可以将其理解为第0 个格子,
你需要在第一个格子里放入p粒小麦,
之后每一个格子放入前两个格子的小麦数之和的小麦
并且要满足第a 个格子放x 粒小麦,第b 个格子放……
说到这,宰相突然发现自己说的满足第a 个格子放x 粒小麦的情况可能不存在……
欺君可是大罪啊!国王看到宰相迟迟不说,自己也烦了!我自己来算!
于是国王拜托你,让你算出第b 个格子应该放几粒小麦
当然,就算答案不存在,你也是要告诉国王的。

Input
该题有多组数据,请读到文件末结束。
对于每一组数据仅一行,3 个正整数a, x, b, 分别表示第a 个格子放了x 粒小麦,
你所需要计算的是第b 个格子的小麦数量。

Output
对于每一次询问,仅1 个整数,为第b 个格子的小麦数量,
若宰相说的情况不存在,那么请输出-1。

Sample Input
1 1 2
3 5 4
3 4 6
12 17801 19

Sample Output
2
8
-1
516847
【样例解释】
对于样例二,f [1] = 2 时,能够满足f [3] = 5,因此宰相没有撒谎,
此时第5 个格子的小麦数应为f [4] = f [2] + f [3] = 3 + 5 = 8.

notes&keys

···50%算法:直接暴力枚举 p,每组数据的时间复杂度 O(ap)
···100%算法:
可以简单打下表手推得到本题与Fibonacci 数列有关,其满足:
f[0]=1, f[1]=p, f[2]=p+1, f[3]=2*p+1……
原本的 Fibonacci 数列满足:f’[0]=1, f’[1]=1, f’[2]=2, f’[3]=3……
已知 f[a]=x,那么在 a>0 的情况下,
g[a]=x-f’[a]=f’[a-1]*(p-1)。
O(a)预处理f ’ [ ](算个三十项吧~) ,因此对于每组数据我们可以O(1)计算出 p
答案不存在的情况即无法整除的情况)。
之后便O(b)递推计算答案。
每组数据的时间复杂度为 O(b)。
*以上为纪中提供题解方法,然鹅本蒟蒻懒得看还是比较喜欢自己的理解方式…

f [ i ] 为斐波那契数列的第i项,则~~(打表+手推)~~找规律可得:
第 i 格应放的麦子数(like通项公式):
f [ i ] * p + f [ i - 1 ]
(预处理三十项斐波那契数,特判若让输出第一项直接输出p)

改了半天的AC代码如下
一定要记得读入数据类型为long long!!!用scanf("%lld%lld%lld", &a, &z, &b)
不然就算定义的是long long,读入用“%d”,也只有五十分儿╭(╯^╰)╮

注:
while(~scanf("%lld%lld%lld", &a, &z, &b))在此处作用相当于
while(scanf("%lld%lld%lld",&a,&x,&b)==3) 相当于
while (scanf("%d%d%d",&a,&x,&b)!=EOF)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll f[31], a, b, p, z;int main()
{f[1] = 1;f[2] = 1;for(int i = 3; i <= 31; ++i){f[i] = f[i - 1] + f[ i - 2];}while(~scanf("%lld%lld%lld", &a, &z, &b)) //一定要记得读入lld!!!!不然只有五十分!! {z -= f[a - 1];p = z / f[a];if(z % f[a] != 0)printf("-1\n");else{if(b == 1)printf("%lld\n", p);elseprintf("%lld\n", p * f[b] + f[b - 1]);//通项公式 }}return 0;
}

T2 休息(rest)

题目描述

jzoj 3462 纪中链接(可能失效)

休息的时候,可以放松放松浑身的肌肉,打扫打扫卫生,感觉很舒服。呵( ̄_, ̄ )
在某一天,某LMZ 开始整理他那书架。
已知他的书有n 本,从左到右按顺序排列。
他想把书从矮到高排好序,而每一本书都有一个独一无二的高度Hi。
他排序的方法是:每一次将所有的书划分为尽量少的连续部分,
使得每一部分的书的高度都是单调下降
然后将其中所有不少于2 本书的区间全部翻转
重复执行以上操作,最后使得书的高度全部单调上升
可是毕竟是休息时间,LMZ 不想花太多时间在给书排序这种事上面。
因此他划分并翻转完第一次书之后,他想计算,
一共执行了多少次翻转操作才能把所有的书排好序
LMZ 惊奇地发现,第一次排序之前,他第一次划分出来的所有区间的长度都是偶数。

Input
第一行一个正整数n, 为书的总数。
接下来一行n个数,第i个正整数Hi,为第i 本书的高度。

Output
仅一个整数,为LMZ 需要做的翻转操作的次数。

Sample Input
6
5 3 2 1 6 4

Sample Output
3
【样例解释】
第一次划分之后,翻转(5,3,2,1),(6,4)。
之后,书的高度为1 2 3 5 4 6,然后便是翻转(5,4)即可。

notes&keys

一个并不明显的性质是,在对原序列进行第一次划分后,
以后的每次划分得到的各个部分都恰好由两个数组成。
这是因为在第一次划分和第一轮的翻转之后,原数列由若干个单调增序列拼接而成,
形式如下:a1, a2…ai, b1, b2…bj…z1…zk.
考虑相邻两个部分,不妨设为 a 部分和 b 部分,其中 ai和 b1前后相邻。
若 ai<b1则可以合并成同一部分,否则会形成块(ai, b1),
并且在下一轮翻转,成为…ai-1, b1, ai, b2…。
可以发现在这以后,由于有 ai-1<ai,则 ai-1与 ai不会在同一个块里;
同理 b1和 b2不会在同一个块里。即,任意连续三个数必定不会是单调递减的。
那么,这以后每次翻转都只会将相邻的逆序对交换。
由于这个算法最终可以正确地得到结果,
所以第一轮以后进行的翻转操作数就等于第一轮之后序列的逆序对数。
而第一轮的翻转数我们可以直接模拟得到。
求一个序列的逆序对数的经典做法是归并排序,同时记录。
时间复杂度 O(nlog2n)
以上为纪中提供题解

来自某不知名巨佬的讲解…
·首先找到最长不上升块儿,两边翻转(相当于两次操作,ans + 2)
*·翻转之后必然内部有序,则下一次翻转只可能发生在块与块的交界处(块与块之间)接下来相当于查找逆序对的过程,每次ans都++

最后答案相当于:
找到最大不上升块,两边都翻转一次之后的逆序对个数+2(已经翻转两次)

类似巨佬思路的一块儿代码
(我没找到巨佬代码…以下代码来自另一“知名”巨佬blt~)
可以直接reserve函数实现翻转操作!!

#include<bits/stdc++.h>
using namespace std;
#define N 100010
int n,a[N],tot,b[N];
long long ans; void merge(int l,int r)  //归并模板
{if(r - l < 1) return;int mid = (l + r) / 2;merge(l,mid);  merge(mid + 1,r);int p1 = l, p2 = mid + 1, t = l;while((p1 <= mid) && (p2 <= r)){if(a[p1] > a[p2]){b[t ++] = a[p2 ++];ans += mid - p1 + 1;}//ans去掉就是归并模板 else b[t ++] = a[p1++];}while(p1 <= mid)  b[t ++] = a[p1 ++];while(p2 <= r)   b[t ++] = a[p2 ++];for(int i = l; i <= r; i ++)a[i] = b[i];
}typedef struct
{int l, r;
}block;block p[N];
int main()
{int cnt = 0;scanf("%d", &n);for(int i = 1; i <= n; i ++) {scanf("%d", &a[i]);if(a[i] > a[i - 1]) {p[cnt].r = i - 1;p[++cnt].l = i;}//找最长不上升块 }p[cnt].r = n;//l,r为块的两头,最后一个的右端即为总的结尾 for(int i = 1; i <= cnt; i++) reverse(a + p[i].l, a + p[i].r + 1), ans++;merge(1, n);printf("%lld",ans);return 0;
}

发现我找到的“标程”反而更难懂…
大致思路一致,具体实现方法不太一样…?
以下是改了很多遍再交才 AC 的 代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 100001;
ll zz[maxn], zcc[maxn];
int n;inline ll read()//快读优化
{ll x = 0, f = 1;char ch = getchar();while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;
} int lowbit(int x)
{return x & (-x);
}void add(int xc, int dd)
{while(xc <= n){zcc[xc] += dd;xc += lowbit(xc);}return;
}int query(int x)
{int sum = 0;while(x > 0){sum += zcc[x];x -= lowbit(x);}return sum;
}int main()
{n = read();ll head, tail;ll ans = 0;for(int i = 1; i <= n; ++i)zz[i] = read();head = 1, tail = 1;for(int i = 1; i <= n; ++i)if(i < n && zz[i] > zz[i + 1])tail++;else{if(head < tail){while(head < tail){swap(zz[head], zz[tail]);head++;tail--;}ans++;}head = tail = i + 1;}for(int i = n; i > 0; --i){ans += query(zz[i]);add(zz[i], 1);}printf("%lld", ans);return 0;
}

T3 军训(training)

题目描述

jzoj 3463 纪中链接(可能失效)

HYSBZ 开学了!今年HYSBZ 有n 个男生来上学,学号为1…n,
每个学生都必须参加军训。在这种比较堕落的学校里,每个男生都会有Gi 个女朋友,而且每个人都会有一个欠扁值Hi。学校为了保证军训时教官不会因为学生们都是人生赢家或者是太欠扁而发生打架事故,所以要把学生们分班,并做出了如下要求:

1.分班必须按照学号顺序来,即不能在一个班上出现学号不连续的情况。
2.每个学生必须要被分到某个班上。
3.每个班的欠扁值定义为该班中欠扁值最高的那名同学的欠扁值。
所有班的欠扁值之和不得超过Limit。
4.每个班的女友指数定义为该班中所有同学的女友数量之和。
在满足条件1、2、3 的情况下,分班应使得女友指数最高的那个班的女友指数最小。

请你帮HYSBZ 的教务处完成分班工作,并输出女友指数最高的班级的女友指数。
输入数据保证题目有解。
看得我人都傻了…

notes&keys

仿佛超出了我智商范围…

·20%算法:
dp,设 f[i,j]表示在 1…i 号人中分班,其欠扁值之和为 j 的最
小班级女友指数,那么 f[i,j]=min(f[k-1,j-maxh(k…i)]+sigmaG(k…i)),
预处理 maxh 和 sigmaG,时间复杂度为 O(n^2Limit)

·40%算法:
既然我们要求双最值,那么我们考虑二分答案,
判断能否满足Σmax(H)<=Limit.
Check 部分可以用 dp 完成。
f[ i ]表示在 1…i 号人中 分 班 所 得 到 的 最 小 Σ max(H) , 那 么 转 移 方 程 应 该 是
f [ i ] = min ( f [ j - 1 ] + maxh ( j…i ) ),
对于 maxh(j…i)可以事先预处理出来。
该算法时间复杂度为 O(n^2log2n)

·X0%算法:
我们必须要优化 dp。
假设我们已经取了 j…i 作为一个班级,其 max(Hi)=r,
如果 Hj-1<=r,且取第 j-1个人不会使得女友数超上限
那么肯定取第 j-1 个人不会比不取要差。
为什么?因为 f[i]是单调不递减
的,因此取了第 j-1 个人既不会使 r 变大,也不会使 f[]变大。因此我们
可以看出有很多决策都是无用的,而有用的决策只会分布在单调递减的 H[ ]上
满足从 j 到 i 的所有 H[ ]中 Hj最大的所有 j 上
于是,我们便建立一个链表连接每一个可用的 j,这种算法的时间复杂度
无法估算,最坏情况可退化为 O(n^2log2n)。但对于某些随机数据而言,这
样的算法是可以拿到分的。对于本道题数据,期望得分 50 至 70 分。

· 100%算法:
在 X0%算法的思想上,我们构造一个单调队列 a[]来维护 H[],
并同时还要维护一个离 i 最远的能够取得到的 j’,使得:
(1) H[a[0]]>H[a[1]]>…>H[a[m]]
(2) a [ 0 ] >= j’ , a [m] = i, sum ( g [ j’ ] …g [ i ] ) <= ans (二分的答案)
但是注意:转移答案的时候,队列里的每一个f [ a [k] ] + h [ a [k+1] ]都可以
转移过来。但是我们发现 f[a[k]]+h[a[k+1]]完全与 i 无关。因此,用集合,用堆,等等,只要用可以随时添加删除元素并查找最小值的数据结构
都可以用来维护最小的 f[a[k]]+h[a[k+1]],这样就可以了。
时间复杂度为 ==O(nlog2n)==至 O(nlog2nlog2n),由你所使用的数据结构所决定。

这道题的代码常数本身较高,请大家注意自己的数据结构代码常数,不要
因为数据结构的原因而超时。

附上本蒟蒻并没有特别看懂虽然看起来好像挺简单的

AC代码

请忽视乱七八糟的变量名…暴躁秃头键盘相邻区域乱打…

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 20005;
ll zz[maxn], jz[maxn], limit, mid, w, ans;
int n, zzz, cc, cz, xc[maxn], next[maxn], a[maxn],c[maxn];int doo(int cw)
{int l = cw, r = n, mid1 = (l + r) / 2;while(l < r){mid1 = (l + r) / 2;    //必须里面也要再来一次mid1=... if(zz[mid1] - zz[cw - 1] >= mid)r = mid1;elsel = mid1 + 1;}return l;
}bool pand()
{memset(jz, 127, sizeof(jz));jz[1] = 0;for(int i = 1; i <= n; ++i){int cw = i, w = xc[cw], k = doo(i);if(zz[k] - zz[i - 1] > mid)k--;while(cw <= k){jz[cw] = min(jz[cw], jz[i] + w);w = xc[cw];cw = next[cw];}jz[k + 1] = min(jz[k + 1], jz[i] + w);      }if(jz[n + 1] > limit)return 0;elsereturn 1;
}int main()
{scanf("%d %d", &n, &limit);for(int i = 1; i <= n; ++i){int cw;cin >> xc[i] >> cw;zz[i] = zz[i - 1] + cw;}cz = 1;a[1] = n + 1;c[1] = 2147483647;for(int i = n; i; --i){while(xc[i] >= c[cz])cz--;next[i] = a[cz];cz++;c[cz] = xc[i];a[cz] = i;}int l = 1, r = zz[n];ans = zz[n];while(l <= r){mid = (l + r) / 2;if(pand()){if(mid < ans)ans = mid;r = mid - 1;}elsel = mid + 1;}cout << ans << endl;
//  return 0;
}

10.30纪中DAY2_小麦亩产一千八(kela) 休息(rest) 军训(training)相关推荐

  1. JZOJ 3461. 【NOIP2013模拟联考5】小麦亩产一千八(kela)

    3461. [NOIP2013模拟联考5]小麦亩产一千八(kela) (Standard IO) Time Limits: 1000 ms  Memory Limits: 262144 KB  Det ...

  2. JZOJ3461【小麦亩产一千八(kela)】

    小麦亩产一千八(kela) 题目描述: "有了金坷垃,肥料一袋能顶两袋撒,小麦亩产一千八,吸收两米下的氮磷钾--",话说HYSBZ(Hengyang School for Boys ...

  3. 【NOIP2013模拟联考5】小麦亩产一千八(kela) (Standard IO)

    Description "有了金坷垃,肥料一袋能顶两袋撒,小麦亩产一千八,吸收两米下的氮磷钾--",话说HYSBZ(Hengyang School for Boys & Z ...

  4. 小麦亩产一千八(jzoj 3461)

    小麦亩产一千八 jzoj 3461 题目大意 给你一个正整数序列:a0,a1,a2a_0,a_1,a_2a0​,a1​,a2​-- a0a_0a0​为1 a1a_1a1​为p ax=ax−1+ax−2 ...

  5. jzoj3461. 小麦亩产一千八 斐波拉契数列

    Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits Description "有了金坷垃,肥料一袋能顶两袋撒,小麦亩产 ...

  6. [jzoj 3461]【NOIP2013模拟联考5】小麦亩产一千八 {Fibonacci数列}

    题目 Description "有了金坷垃,肥料一袋能顶两袋撒,小麦亩产一千八,吸收两米下的氮磷钾--",话说HYSBZ(Hengyang School for Boys & ...

  7. JZOJ6月20日提高组T1 小麦亩产一千八

    JZOJ6月20日提高组T1 小麦亩产一千八 题目 Description Input Output Sample Input Data Constraint 分析 Code 题目 Descripti ...

  8. [Jzoj] 3461. 小麦亩产一千八

    题目描述 "有了金坷垃,肥料一袋能顶两袋撒,小麦亩产一千八,吸收两米下的氮磷钾--",话说HYSBZ学识渊博孩纸们一讲到粮食,都会想起印度那个著名的故事:国王要在第一个格子里放入一 ...

  9. 【NOIP2013模拟联考5】小麦亩产一千八题解

    Description "有了金坷垃,肥料一袋能顶两袋撒,小麦亩产一千八,吸收两米下的氮磷钾--",话说HYSBZ(Hengyang School for Boys & Z ...

最新文章

  1. Java B2B2C o2o多用户商城 springcloud架构 (六)分布式配置中心(Spring Cloud Config)
  2. UVA 220 Othello
  3. HDU 1814 Peaceful Commission
  4. excel xml mysql_数据库表转换为xml格式,excel转换为xml格式文件
  5. Spring源码:AOP转文
  6. 为什么计算机时间要从1970年1月1日开始算起
  7. 使用js、jquery完成省市二级联动
  8. Android Studio NDK开发
  9. 数据包的忽略打印与脱敏打印
  10. 桌面图标分类软件Fences的缺点
  11. 输入水仙花数的位数 c语言,水仙花数,水仙花数c语言
  12. cleaned_data
  13. python中inf_python inf是什么意思
  14. 在电子电路中,为什么要进行电气隔离?
  15. (numpy)python中Array的常用函数
  16. Mac系统自带中文输入法英文标点
  17. 解决redis缓存穿透、redis缓存雪崩问题
  18. Difficulties vanish when faced boldly.
  19. js之 实现浏览器下载图片保存到本地
  20. [NLP]如何进行情感分析

热门文章

  1. 解决EMC、EMI传导干扰的八大方法
  2. 你要学习,你要学习,你要学习 1
  3. SINS/GNSS组合导航:SINS误差模型
  4. 大数据分析师工作内容
  5. cordova build android 出错问题汇总
  6. 什么邮箱最安全?教你三招快速提升邮箱安全性方法,职场人必看!
  7. 《爱上跑步的13周》,让你拥有健康美丽的人生
  8. 【双系统】win10和ubuntu双系统(UEFI)删除ubuntu
  9. 语音合成接口整理_各平台语音合成接口
  10. Html5结合nodejs实现保存图片到硬盘或数据库的方法