[APIO2016]
2016的题貌似是韩国棒子出的,好丧啊.... 看了题解还想了好久......
-------------------------------------------------
A.Boat
有n个数,每个数字可取[li,ri]内的任意整数si,但是要求对于任意i<j,都有si<sj,求方案数 n<=500,l,r<=10^9
题解:首先离散,然后不同区间的方案数很好转移,我们考虑相同区间的方案数,发现是一个差分了多次的数列,如果区间长度是l,选m个这样的区间,那么方案数是11111...差分m次后的第l项。然后我们可以发现这个其实是一个组合数,等于C(m,m+l)。我们用f[i][j]表示第i个选第j个区间的方案数,然后我们把f数组前缀和之后推出公式,
f[i][j]=∑C(i-i'-1,i-i'+l-1) * f[i'-1][j-1]
复杂度n^3
#include<iostream>
#include<cstdio>
#include<algorithm>
#define mod 1000000007
#define MAXN 1000
#define int long long
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} int tot=-,n,L[*MAXN+];
int l2[MAXN*+],l[MAXN+],r[MAXN+];
int f[MAXN+][MAXN*+];
int inv[MAXN+],p[MAXN+]; main()
{
p[]=inv[]=p[]=inv[]=;
for(int i=;i<=MAXN;i++)
{
p[i]=1LL*p[i-]*i%mod;
inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
}
//for(int i=2;i<=MAXN;i++) inv[i]=1LL*inv[i]*inv[i-1]%mod;
n=read();
for(int i=;i<=n;i++)
{
l[i]=l2[i*-]=read();
r[i]=l2[i<<]=read();l2[i<<]+=;
}
sort(l2+,l2+n*+);
for(int j=;j<=n*;j++)if(l2[j]!=l2[j-])
l2[++tot]=l2[j]; tot++;
for(int i=;i<tot;i++) L[i]=l2[i]-l2[i-];
for(int i=;i<=n;i++)
{
l[i]=upper_bound(l2,l2+tot,l[i])-l2;
r[i]=upper_bound(l2,l2+tot,r[i])-l2;
// cout<<l[i]<<" "<<r[i]<<endl;
}
for(int i=;i<tot;i++) f[][i]=;
for(int i=;i<=n;i++)
{
f[i][]=;
for(int j=l[i];j<=r[i];j++)
{
f[i][j]=(long long)L[j]*f[i-][j-]%mod;//cout<<f[i][j]<<endl;
int now=;long long c=L[j]-;
for(int k=i-;k;--k)
if(l[k]<=j&&j<=r[k])
{
now++;
c=c*(long long)(L[j]+now-)%mod*inv[now]%mod;
if(!c)break;
f[i][j]=(f[i][j]+(long long)f[k-][j-]*c)%mod;
}
}
for(int j=;j<tot;j++)
f[i][j]=((long long)f[i][j]+f[i-][j]+f[i][j-]-f[i-][j-]+mod)%mod;
// for(int j=1;j<tot;j++)
// cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
}
cout<<(long long)(f[n][tot-]-+mod)%mod;
return ;
}
B.给定一棵n个非叶节点,m个叶节点的树,有边权,定义修改边权的费用为前后边权的差的绝对值,你要让所有叶节点到根节点的距离相同,但又不能把边权改成负数,求最小费用。
n,m<=300000
题解:我们用f[i][j]表示第i个点,子树中的叶节点到它的距离都是j的最小费用,那么f[i][0]=∑Wjk (jk都在子树i中)。
很显然,f函数是一个下凸的函数,并且存在一些拐点,拐点前后斜率变化是1,但是拐点可以重在某一个点上。只有一个叶节点时,拐点有两个,且都为于0,凸壳形状像一个绝对值函数。
所以我们只要知道所有拐点,就可以知道这个函数啦。
我们考虑向一个子树添加边时候的影响,由于w可以无限增大,在一定大小后只修改这一条边一定最优,斜率肯定都是1,所以对于斜率大于1的部分我们都可以舍去,即弹掉所有原来斜率大等0的拐点。
这样一次合并我们实际上只把它向右平移了一下。需要删除和合并操作,所以写一个可并堆就好啦。
复杂度(n+m)log(n+m)
#include<iostream>
#include<cstdio>
#define MN 600000
#define ll long long
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} int n,m,fa[MN+],in[MN+];
ll w[MN+],ans=; struct Heap{
Heap *l,*r;
ll p;int d;
Heap(ll _p):p(_p),l(),r(),d(){};
inline friend int dis(Heap*x){return x?x->d:;}
friend Heap* Merge(Heap*x,Heap*y)
{
if(!x) return y;if(!y) return x;
if(x->p<y->p) swap(x,y);
x->r=Merge(x->r,y);
if(dis(x->r)>dis(x->l)) swap(x->l,x->r);
x->d=dis(x->r)+; return x;
}
}*s[MN+],*a,*b; int main()
{
n=read();m=read();n+=m;
for(int i=;i<=n;i++)
{++in[fa[i]=read()];ans+=(w[i]=read());}
for(int i=n;i>;i--)
{
if(!s[i]) s[i]=Merge(new Heap(),new Heap());
for(int j=;j<in[i];j++)
s[i]=Merge(s[i]->l,s[i]->r);
a=new Heap(s[i]->p+w[i]);s[i]=Merge(s[i]->l,s[i]->r);
b=new Heap(s[i]->p+w[i]);s[i]=Merge(s[i]->l,s[i]->r);
s[fa[i]]=Merge(s[fa[i]],Merge(s[i],Merge(a,b)));
}
int top=;
while(s[])w[++top]=s[]->p,s[]=Merge(s[]->l,s[]->r);w[top+]=;
for(int i=top;m;m--,i--) ans-=(w[i]-w[i+])*m;
printf("%lld\n",ans);
return ;
}
C.Gap
给定一个长度为n的严格递增数列,你每次可以询问一个数字区间的最大值,最小值,求最大差分。n<=100000
题解:对于subtask1,询问次数不超过(n+1)/2,我们枚举左右节点查,然后缩短这个区间就好啦。
对于subtask2,询问的区间含有k个数时费用是k+1,要让费用不超过3n。我们先求最大值x和最小值y,显然答案不会低于(y-x)/(n-1),所以我们把数字分块,每块内不存在答案,都询问一次就行了。
#include "gap.h"
#include<algorithm>
#include<iostream>
using namespace std;
#define ll long long
#define INF 1000000000000000000LL
ll s[];
ll ans=;
int cnt=; ll solve(int x)
{
ll l,r;
MinMax(,INF,s+,s+x);cnt=;int i=,j=x-;
for(l=s[]+,r=s[x]-;i<=j;l=s[i++]+,r=s[j--]-)
{
MinMax(l,r,s+i,s+j);
}
for(int i=;i<=x;i++)
ans=max(ans,s[i]-s[i-]);
return ans;
} ll findGap(int T, int N)
{
if(T==) return solve(N);
if(N==) return ;
MinMax(,INF,s+,s+);cnt=;
ll p=(s[]-s[]-)/(N-)+;
for(ll i=s[]+;i<=s[]-;i+=p)
{
MinMax(i,min(i+p-,s[]-),s+cnt+,s+cnt+);
if(s[cnt+]>)cnt+=;
}
sort(s+,s+cnt+);
for(int i=;i<=cnt;i++)
ans=max(ans,s[i]-s[i-]);
return ans;
}
[APIO2016]的更多相关文章
- BZOJ 4584 luogu P3643: [Apio2016]赛艇
4584: [Apio2016]赛艇 Time Limit: 70 Sec Memory Limit: 256 MB[Submit][Status][Discuss] Description 在首尔 ...
- [洛谷P3643] [APIO2016]划艇
洛谷题目链接:[APIO2016]划艇 题目描述 在首尔城中,汉江横贯东西.在汉江的北岸,从西向东星星点点地分布着 \(N\) 个划艇学校,编号依次为 \(1\) 到 \(N\).每个学校都拥有若干艘 ...
- 【APIO2016】Fireworks[DP 可并堆维护凸包优化]
4585: [Apio2016]烟火表演 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 100 Solved: 66[Submit][Status] ...
- 【BZOJ4584】[Apio2016]赛艇 DP
[BZOJ4584][Apio2016]赛艇 Description 在首尔城中,汉江横贯东西.在汉江的北岸,从西向东星星点点地分布着个划艇学校,编号依次为到.每个学校都拥有若干艘划艇.同一所学校的所 ...
- UOJ #205/BZOJ 4585 【APIO2016】Fireworks 可并堆+凸包优化Dp
4585: [Apio2016]烟火表演 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 115 Solved: 79[Submit][Status] ...
- Loj #2568. 「APIO2016」烟花表演
Loj #2568. 「APIO2016」烟花表演 题目描述 烟花表演是最引人注目的节日活动之一.在表演中,所有的烟花必须同时爆炸.为了确保安全,烟花被安置在远离开关的位置上,通过一些导火索与开关相连 ...
- 「APIO2016」烟花表演
「APIO2016」烟花表演 解题思路 又是一道 solpe trick 题,观察出图像变化后不找一些性质还是挺难做的. 首先令 \(dp[u][i]\) 为节点 \(u\) 极其子树所有叶子到 \( ...
- 写在APIO2016之前
时间过得真快.仿佛前天的我还在为联赛的MLE悲伤,昨天的我还在为省选看错题而崩溃,今天就到了APIO的前夜了.虽然明天不是正赛,但我的学弟们都是明天离开.也就是说,我只能为在遥远帝都的他们默默地祈祷了 ...
- P3643 [APIO2016]划艇
P3643 [APIO2016]划艇 题意 一个合法序列可表示为一个长度为 \(n\) 的序列,其中第 \(i\) 个数可以为 0 或 \([l_i,r_i]\) 中一个整数,且满足所有不为零的数组成 ...
- CTSC2016&&APIO2016滚粗记&&酱油记&&游记<del>(持续更新)</del>
挖一波坑 #include <cstdio> using namespace std; int main(){ puts("转载请注明出处:http://www.cnblogs. ...
随机推荐
- 玩转Leveldb原理及源码--拙见1
可以说是不知天高地厚.. 可以说是班门弄斧.. 但是,我今天还就这样走了,我喜欢!!!!!! 注:后续文章,限于篇幅,不懂名词都有 紫色+下划线 超链接,有兴趣,可以查阅: 网上关于Leveldb 的 ...
- python之路--day15--常用模块之logging模块
常用模块 1 logging模块 日志级别:Noset (不设置) Debug---(调试信息)----也可用10表示 Info--(消息信息)----也可用20表示 Warning---(警告信息) ...
- New UWP Community Toolkit - DeveloperTools
概述 UWP Community Toolkit 中有一个开发者工具集 DeveloperTools,可以帮助开发者在开发过程中进行 UI 和功能的调试,本篇我们结合代码详细讲解 Develope ...
- Python内置函数(34)——filter
英文文档: filter(function, iterable) Construct an iterator from those elements of iterable for which fun ...
- HTTP协议扫盲(七)请求报文之 GET、POST-FORM 和 POST-FILE
一.get 1.页面代码 2.请求报文 3.小结 get请求没有报文体,所以请求报文没有content-type url上的query参数param11=val11¶m12=val12 ...
- Docker学习笔记 - Docker的简介
传统硬件虚拟化:虚拟硬件,事先分配资源,在虚拟的硬件上安装操作系统,虚拟机启动起来以后资源就会被完全占用. 操作系统虚拟化:docker是操作系统虚拟化,借助操作系统内核特性(命名空间.cgroups ...
- Python之格式化输出,初始编码以及运算符
一.题型 1.使用while循环输入 1 2 3 4 5 6 8 9 10 count = 0 while count < 10: count += 1 #count = count + ...
- 归档(NSKeyedArchiver)的使用
归档的使用,是归于使用保存数据,但是一些简单的数据,如数组,字典等基本的数据类型,往往不使用在归档中,归档和plist以及UserDefaults最大的区别就在于,前者可以存放自定义的数据类型,而后两 ...
- JavaScript是如何面向对象的
一.引言 在16年的10月份,在校内双选会找前端实习的时候,hr问了一个问题:JavaScript的面向对象理解吗?我张口就说"JavaScript是基于原型的!".然后就没什么好 ...
- hadoop fs:du统计hdfs文件(目录下文件)大小的用法
hadoop fs 更多用法,请参考官网:http://hadoop.apache.org/docs/r1.0.4/cn/hdfs_shell.html 以下是我的使用统计文件时使用的记录: [t@d ...