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 = 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 tot=-1,n,L[2*MAXN+5];
int l2[MAXN*2+5],l[MAXN+5],r[MAXN+5];
int f[MAXN+5][MAXN*2+5];
int inv[MAXN+5],p[MAXN+5];main()
{p[0]=inv[0]=p[1]=inv[1]=1;for(int i=2;i<=MAXN;i++){p[i]=1LL*p[i-1]*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=1;i<=n;i++){l[i]=l2[i*2-1]=read();r[i]=l2[i<<1]=read();l2[i<<1]+=1;}sort(l2+1,l2+n*2+1);for(int j=1;j<=n*2;j++)if(l2[j]!=l2[j-1])l2[++tot]=l2[j];  tot++;for(int i=1;i<tot;i++) L[i]=l2[i]-l2[i-1]; for(int i=1;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=0;i<tot;i++) f[0][i]=1;for(int i=1;i<=n;i++){f[i][0]=1;for(int j=l[i];j<=r[i];j++){f[i][j]=(long long)L[j]*f[i-1][j-1]%mod;//cout<<f[i][j]<<endl;int now=1;long long c=L[j]-1;for(int k=i-1;k;--k)if(l[k]<=j&&j<=r[k]){now++;c=c*(long long)(L[j]+now-2)%mod*inv[now]%mod;if(!c)break;f[i][j]=(f[i][j]+(long long)f[k-1][j-1]*c)%mod;}}for(int j=1;j<tot;j++)f[i][j]=((long long)f[i][j]+f[i-1][j]+f[i][j-1]-f[i-1][j-1]+mod)%mod;//  for(int j=1;j<tot;j++)//  cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
    }cout<<(long long)(f[n][tot-1]-1+mod)%mod;return 0;
}

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 = 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 n,m,fa[MN+5],in[MN+5];
ll w[MN+5],ans=0;struct Heap{Heap *l,*r;ll p;int d;Heap(ll _p):p(_p),l(0),r(0),d(1){};inline friend int dis(Heap*x){return x?x->d:0;}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)+1;return x;}
}*s[MN+5],*a,*b;int main()
{n=read();m=read();n+=m;for(int i=2;i<=n;i++){++in[fa[i]=read()];ans+=(w[i]=read());}for(int i=n;i>1;i--){if(!s[i]) s[i]=Merge(new Heap(0),new Heap(0));for(int j=1;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=0;while(s[1])w[++top]=s[1]->p,s[1]=Merge(s[1]->l,s[1]->r);w[top+1]=0;for(int i=top;m;m--,i--) ans-=(w[i]-w[i+1])*m;printf("%lld\n",ans);return 0;
}

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[200005];
ll ans=0;
int cnt=0;ll solve(int x)
{ll l,r;MinMax(0,INF,s+1,s+x);cnt=2;int i=2,j=x-1;for(l=s[1]+1,r=s[x]-1;i<=j;l=s[i++]+1,r=s[j--]-1){MinMax(l,r,s+i,s+j);}for(int i=2;i<=x;i++)ans=max(ans,s[i]-s[i-1]);return ans;
}ll findGap(int T, int N)
{if(T==1) return solve(N);if(N==1) return 0;MinMax(0,INF,s+1,s+2);cnt=2;ll p=(s[2]-s[1]-1)/(N-1)+1;for(ll i=s[1]+1;i<=s[2]-1;i+=p){MinMax(i,min(i+p-1,s[2]-1),s+cnt+1,s+cnt+2);if(s[cnt+1]>0)cnt+=2;}sort(s+1,s+cnt+1);for(int i=2;i<=cnt;i++)ans=max(ans,s[i]-s[i-1]);return ans;
}

转载于:https://www.cnblogs.com/FallDream/p/apio2016.html

[APIO2016]相关推荐

  1. Loj #2568. 「APIO2016」烟花表演

    Loj #2568. 「APIO2016」烟花表演 题目描述 烟花表演是最引人注目的节日活动之一.在表演中,所有的烟花必须同时爆炸.为了确保安全,烟花被安置在远离开关的位置上,通过一些导火索与开关相连 ...

  2. 「APIO2016」烟花表演

    「APIO2016」烟花表演 解题思路 又是一道 solpe trick 题,观察出图像变化后不找一些性质还是挺难做的. 首先令 \(dp[u][i]\) 为节点 \(u\) 极其子树所有叶子到 \( ...

  3. APIO2016 Fireworks

    APIO2016 Fireworks 题意: 题目传送门 题解: 第一眼想到的应该是一个\(Dp\),我们记\(f_{u, i}\)表示\(u\)这个子树中,所有叶子节点到\(u\)的距离都为\(i\ ...

  4. [APIO2016]划艇

    [APIO2016]划艇 总共只有2*n段.分段进行DP 简单的方法是: 外层枚举段数j,f[i]表示,当前枚举到j的时候,以(i,j)结尾(必须选择(i,j))的方案数,枚举一个f(p,1~j-1) ...

  5. BZOJ 4584 [Apio2016]赛艇

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4584 题解 首先将BiB_iBi​加111,把派出的数量变成左闭右开的区间,将AiA_i ...

  6. 【APIO2016】Fireworks【闵可夫斯基和】【凸包向量和】【可并堆】

    题意:给一棵带边权的树,可以花费 111 的代价把一条边的边权修改 111,一条边可以修改多次,求使得根到叶子距离相等的最小代价. n≤3×105n\leq 3\times 10^5n≤3×105 先 ...

  7. [APIO2016] 划艇(dp + 组合数 + 前缀和优化)

    problem luogu-P3643 solution 有个显然的暴力 dpdpdp.设 dp(i,j):dp(i,j):dp(i,j): 到了第 iii 个学校,其参加且派出 jjj 个划艇的方案 ...

  8. P3642 [APIO2016]烟火表演(左偏树、函数)

    解析 感觉是左偏树的神题了. 首先有一个比较显然的结论,一个合法的方案中,两个叶子到它们 lca\text{lca}lca 的距离必须相等. 考虑设计 dp\text{dp}dp : fi,xf_{i ...

  9. [APIO2016]烟火表演

    链接:https://www.luogu.org/problemnew/show/P3642 跟上一道题类似但更难,首先也是观察出在某个节点代价是下凸的函数,并且得到转移方程: 1.x<=L f ...

最新文章

  1. c java utf 8_如何对javac设置encoding utf 8
  2. 1、SpringBoot------表单校验
  3. 201521123054《Java程序设计》第1周学习总结
  4. 通用计划明年推出自动驾驶出租车共享服务,可定制化设计车辆
  5. 心情舒畅,升级到u10.04了
  6. Android TelephonyManager类
  7. i.MX6 设备树 GPIO 默认值
  8. Opencv中convertTo函数
  9. HDOJ1008 Elevator
  10. 实验01 使用网络协议分析仪Wireshark
  11. kux文件怎么打开 苹果手机如何观看kux视频
  12. 腾讯日常实习面试经历
  13. nova Evacuate
  14. 6.S081参考书笔记 —— 第7章调度、进程交互
  15. java基于ssm的自助旅游管理系统
  16. MySQL中查看数据库
  17. CC2640R2F之配对绑定与解除绑定篇
  18. MySQL中Invalid default value错误解决方法
  19. matlab 双y轴对数坐标 误差线,matlab双y轴添加误差棒(转载)
  20. varchar 和 char 的区别

热门文章

  1. multi task训练torch_手把手教你使用PyTorch(2)-requires_gradamp;computation graph
  2. python中_python中的一些用法总结
  3. 基于matlab的车流量检测,求解释代码,一段交通车流量检测的代码
  4. imagex使用方法_Microsoft OneDrive 的使用心得,真香
  5. Java基础学习-IO流
  6. poj 1083 Moving Tables
  7. 十五. Python基础(15)--内置函数-1
  8. [Unity3D]unity3d5.0简单的调用摄像头
  9. mysql outfile csv_sql-MySQL导出到outfile:CSV转义字符
  10. 9、Flutter 实现 生成二维码