2017.07.13【NOIP提高组】模拟赛B组小结

来源:互联网 发布:复合视频矩阵 编辑:程序博客网 时间:2024/05/28 23:21

30+50+80=160,rank 7,水法很重要

T1jzoj4594. 【NOIP2016模拟7.8】Dynamic len

Description

有n个数编号从0→n-1,两种操作:
Q L R:询问编号为L→R-1的数中共有多少种不同的数
M X Y:将编号为X的数改为Y
共有m个操作

Input

第一行两个数n,m
接下来m行,每行有两种形式,如题目描述

Output

对于每一个Q操作,输出相应的答案

Sample Input

7 4
1 2 1 3 2 1 4
Q 1 6
M 3 2
Q 1 6
Q 3 5

Sample Output

3
2
1

Data Constraint

30% n,m<=10000
100% n,m<=50000
数的范围<=1000000
想法:
只会暴力的我太弱了
莫队 不会 70行
树套数 不会 200行
平衡树 不会 200行
分块 不会 220行
必须C++

T2jzoj4298. 【NOIP2015模拟11.2晚】我的天

Description

很久很以前,有一个古老的村庄——xiba村,村子里生活着n+1个村民,但由于历届村长恐怖而且黑暗的魔法统治下,村民们各自过着独立的生活,完全没有意识到其他n个人的存在。
但有一天,村民xiba臻无意中也得到了魔法,并发现了这个恐怖的事实。为了反抗村长,他走遍了全世界,找到了其他n个村民,并组织他们发动革命。但让这n个素不相识的村民(xiba臻已跟他们认识)同心协力去抵抗村长是很困难的,所以xiba臻决定先让他们互相认识。
这里,xiba臻用了xiba村特有的xiba思维:先让这n个人排成一列,并依次从1-n标号。然后每次xiba臻会选出一个区间[l, r],在这个区间中的人会去认识其他在这个区间中的人,但已经认识过得不会再去认识。这样,进行m次操作后,xiba臻认为这n个人能认识到许多人。
但是,为了精确地知道当前有多少对人已经认识了,xiba臻想要知道每次操作后会新产生出多少对认识的人,但这已是xiba思维无法解决的事了,你能帮帮他吗?

Input

第一行两个整数n,m。
接下来m行每行两个整数li,ri,表示每次操作的区间。

Output

共m行,每行一个整数ans_i,表示第i次操作后新产生出ans_i对认识的人。

Sample Input

5 5
2 3
2 4
3 5
1 5
2 4

Sample Output

1
2
2
5
0

Data Constraint

对于20%的数据,1≤n,m≤100。
对于50%的数据,1≤n,m≤5000。
对于100%的数据,1≤n,m≤300000,1≤li≤ri≤n。
想法:
设f[i]表示i认识了f[i]~i的人
每次操作f[i]=min(f[i],l),同时记录答案(l<=i<=r)
很明显f是单调不递减的
if (f[i]<=l) break;

T3jzoj3432. 【GDOI2014模拟】服务器

Description

我们需要将一个文件复制到n个服务器上,这些服务器的编号为S1, S2, …, Sn。

首先,我们可以选择一些服务器,直接把文件复制到它们中;将文件复制到服务器Si上,需要花费ci > 0的置放费用。对于没有直接被复制文件的服务器Si来说,它依次向后检查Si+1, Si+2, …直到找到一台服务器Sj:Sj中的文件是通过直接复制得到的,于是Si从Sj处间接复制得到该文件,这种复制方式的读取费用是j – i(注意j>i)。另外,Sn中的文件必须是通过直接复制得到的,因为它不可能间接的通过别的服务器进行复制。我们设计一种复制方案,即对每一台服务器确定它是通过直接还是间接的方式进行复制(Sn只能通过直接方式),最终使每一台服务器都得到文件,且总花费最小。

Input

输入文件的第一行有一个整数n,表示服务器的数目。输入文件的第二行有n个整数,顺数第i个表示ci:在Si上直接复制文件的费用。

Output

输出文件中只包含一个整数,即最少需要花费的费用。

Sample Input

10

2 3 1 5 4 5 6 3 1 2

Sample Output

18

Data Constraint

60%的数据中,1 <= n <= 1 000

100%的数据中,1 <= n <= 1 000 000

80%的数据中, 1 <= ci <= 50

100%的数据中,1 <= ci <= 1 000 000 000

最终结果可能较大,请注意选择适当的数据类型进行计算。

Hint
这里写图片描述
想法:
设f[i]表示1~i中,第i个必须使用直接复印的方法
f[i]=min(f[j]+(i-j-1)*(i-j)/2)+a[i]//第j+1~i-1台去第i台复印
很明显n^2
考虑斜率优化+单调队列
假设由j转移到i比由k转移到i更优,(j《k)则有
Fj+(i−j)∗(i−j−1)2《Fk+(i−k)∗(i−k−1)2
两边同乘2,得
2 * Fj+(i−j)∗(i−j−1)<2 * Fk+(i−k)∗(i−k−1)
拆括号,得
2 * Fj+i2+j2 - 2ij -i+j<2 * Fk+i2+k2 - 2ik -i+k
两边同时减去(i2-i)
2 * Fj+j2 - 2ij+j<2 * Fk+k2 - 2ik+k
把含有i的项全部移到右边,剩下不含有i的项全部移到右边,得
2 * (Fj-Fk)+j2-k2+j - k<2ij - 2ik
两边同时除去(2j- 2k),(2j- 2k)<0

2∗(Fj−Fk)+j2−k2+j−k2j−2k> i
设Gi=Fi+j2+j,Vi=2i,则原不等式变为

Gj−GkVj−Vk>i
仔细观察左边的式子,咦,好像有点熟悉是吧?

你没有看错,那就是传说中的圣斗士斜率!

所以当Gj−GkVj−Vk>i由j转移过来比由k转移过来更优。
反之,当Gj−GkVj−Vk《i由k转移过来比由j转移过来更优。

我们维护一个单调队列,队列里相邻的两个元素的斜率是单调递增。
当我们找到一个i时,发现队头元素l,以及对头后面的元素p,
发现Gl−GpVl−Vp《i,说明此时由l转移过来已经没有由p转移过来优了。

上面的式子也说明Gl−GpVl−Vp《i+1《i+2《……《n,也就说明从此以后,由l转移过来都不会由p转移过来优了,所以这时我们可以抛弃队头了,因为再也不会有任何卵用了。

完成Fi的赋值后,我们把i放到队尾。
这时我们发现由i转移过来可能比队内其他元素转移过来更加优,于是我们也可以从队尾往前更新。

设函数kd(j,k)=Gj−GkVj−Vk,队列最后一个元素的下标为r,该队列为d,
则如果kd(dr−2,dr−1)>kd(dr−1,dr),则dr−1一定不是最优的,可以宣布报废,将其踢出队列,为什么呢?

Reason One

从数的角度解释。
分类讨论
<1>如果i>kd(dr−2,dr−1)>kd(dr−1,dr),则dr−1不比dr更优。
<2>如果kd(dr−2,dr−1)>i>kd(dr−1,dr),则dr−1不比dr−2更优。
<3>如果kd(dr−2,dr−1)>kd(dr−1,dr)>i,则dr−1不比dr−2更优。
综上所述,无论如何,dr−1都不是这三个元素中最优的,是个累赘,应该丢弃。

Reason Two

从形的角度解释。
kd(dr−2,dr−1)>kd(dr−1,dr)的情况如下图
这里写图片描述
如下情况不满足队列的两两元素之间的斜率单调性,于是把dr−1去掉,这样新形成的最后两个元素的斜率会比原来的最后两个元素的斜率大,这样既可维护斜率单调性。

这就是斜率优化的全过程,对于每个元素,进队一次,出队一次,所以总时间复杂度为O(n),可以拿100分。

#include <cstdio>#include <cstdlib>#include <cmath>#include <ctime>#include <algorithm>using namespace std;long long n,m,r,l,f[1000001],a[1000001],d[1000001],j;int i;long long  xl(long long j,long long k){    return (2*f[j]+j*j+j-2*f[k]-k*k-k)/(2*j-2*k);}long long min1(long long x,long long y){    if (x<y) return x;else return y;}int main(){    freopen("a.in","r",stdin);    scanf("%lld",&n);    for (i=1;i<=n;i++)scanf("%lld",&a[i]);    for (i=1;i<=n;i++)    {        j=i;        f[j]=(j-1)*j/2+a[i];    }    d[1]=1;    r=1;    l=1;    for (i=2;i<=n;i++)    {        double x=xl(d[l],d[l+1]);        j=i;        while ((l<r)&(xl(d[l],d[l+1])<j)) l++;        f[j]=min1(f[j],f[d[l]]+(j-d[l])*(j-d[l]-1)/2+a[j]);        while ((l<r)&(xl(d[r-1],d[r])>xl(d[r],j))) r--;        d[++r]=j;    }    printf("%lld\n",f[n]);}
阅读全文
1 0
原创粉丝点击