我好菜啊都不会

T1.boats

题目大意:给你N段区间,按顺序决定每段区间可以选一个数或不选,若选则选的这个数必须大于所有在这之前选的数,求有多少种方案。(N<=500,区间在[1,1e9]范围内)

思路:我的做法比较奇怪……根据DP的思路,题目可以转化为一个数列一开始0的位置是1其他都是0,然后每次把一个区间里的数全部变成原来数列的前缀和,然后我按权值分了个块,把区间左右端点离散后如果相邻的差超过k就分成相差不超过k的几块,预处理出一开始都为1的各个长度的区间经过若干次前缀和后和为多少,我们就可以把一个区间的和表示成有几种初始值,每种进行若干次前缀和后的总和,每次操作把一个新的值插入离散出来的区间里,利用预处理的信息算答案(有点难说清楚,感兴趣的参见代码实现……),复杂度O(kn+(1e9/k+n)*n^2),k为块大小,子任务制得分58/100(最后一个T),后来发现多次前缀和就是组合数,于是复杂度变成O(k+(1e9/k+n)*n^2),好像就能过了。

暴力算前缀和

#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
int x;char c;
while((c=getchar())<''||c>'');
for(x=c-'';(c=getchar())>=''&&c<='';)x=(x<<)+(x<<)+c-'';
return x;
}
#define MN 500
#define MC 11000
#define K 100000
#define MOD 1000000007
int l[MN+],r[MN+],c[MC+],cn;
int f[MN+][K+],s[MC+],t[MC+],p[MC+][MN+];
inline int mod(int x){return x>=MOD?x-MOD:x;}
int main()
{
int n=read(),i,j,k,x,v;
for(i=;i<=K;++i)f[][i]=i;
for(i=;i<=n;++i)for(j=;j<=K;j+=)
f[i][j ]=mod(f[i][j-]+f[i-][j ]),
f[i][j+]=mod(f[i][j ]+f[i-][j+]),
f[i][j+]=mod(f[i][j+]+f[i-][j+]),
f[i][j+]=mod(f[i][j+]+f[i-][j+]);
for(i=;i<=n;++i)c[++cn]=l[i]=read()-,c[++cn]=r[i]=read();
sort(c+,c+cn+);
for(i=,j=;i<=cn;++i)if(c[i]!=c[j])c[++j]=c[i];cn=j;
for(i=,j=cn;i<j;++i)for(k=c[i];c[i+]-k>K;)c[++cn]=k+=K;
sort(c+,c+cn+);
for(i=;i<=n;++i)for(j=x=;j<=cn;++j)
if(c[j-]>=l[i]&&c[j]<=r[i])
{
p[j][t[j]++]=x;x=mod(x+s[j]);v=c[j]-c[j-];
for(k=s[j]=;k<t[j];++k)
s[j]=(s[j]+1ll*p[j][k]*f[t[j]-k][v])%MOD;
}
else x=mod(x+s[j]);
for(i=,x=;i<=cn;++i)x=mod(x+s[i]);
printf("%d",x);
}

组合数

#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
int x;char c;
while((c=getchar())<''||c>'');
for(x=c-'';(c=getchar())>=''&&c<='';)x=(x<<)+(x<<)+c-'';
return x;
}
#define MN 500
#define MC 1100
#define K 10000000
#define MOD 1000000007
int l[MN+],r[MN+],c[MC+],cn;
int f[K*+],vf[K*+],s[MC+],t[MC+],p[MC+][MN+];
inline int mod(int x){return x>=MOD?x-MOD:x;}
inline int inv(int x)
{
int r=,y=MOD-;
for(;y;y>>=,x=1LL*x*x%MOD)if(y&)r=1LL*r*x%MOD;
return r;
}
int main()
{
int n=read(),i,j,k,x,v;
for(i=f[]=;i<=K<<;++i)f[i]=1LL*f[i-]*i%MOD;
for(vf[i=K<<]=inv(f[K<<]);i--;)vf[i]=1LL*vf[i+]*(i+)%MOD;
for(i=;i<=n;++i)c[++cn]=l[i]=read()-,c[++cn]=r[i]=read();
sort(c+,c+cn+);
for(i=,j=;i<=cn;++i)if(c[i]!=c[j])c[++j]=c[i];cn=j;
for(i=,j=cn;i<j;++i)for(k=c[i];c[i+]-k>K;)c[++cn]=k+=K;
sort(c+,c+cn+);
for(i=;i<=n;++i)for(j=x=;j<=cn;++j)
if(c[j-]>=l[i]&&c[j]<=r[i])
{
p[j][t[j]++]=x;x=mod(x+s[j]);v=c[j]-c[j-];
for(k=s[j]=;k<t[j];++k)
s[j]=(s[j]+1LL*p[j][k]*f[t[j]-k+v-]%MOD*vf[t[j]-k]%MOD*vf[v-])%MOD;
}
else x=mod(x+s[j]);
for(i=,x=;i<=cn;++i)x=mod(x+s[i]);
printf("%d",x);
}

T2.fireworks

题目大意:给出一棵带边权的树,调整树上边长的消耗是调整后的减去调整前的绝对值,求使根节点到所有叶节点距离相等的最小花费,边长必须大等0。(叶节点个数M<=300,000,每个非叶节点除连向父亲外至少连2条边)

思路:不会,打了个中位数乱贪心,好像会把边权弄成负的所以挂了,捆绑测试只有7分……

#include<cstdio>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
#define ll long long
inline int read()
{
int x=;char c;
while((c=getchar())<''||c>'');
for(;c>=''&&c<='';c=getchar())x=(x<<)+(x<<)+c-'';
return x;
}
#define MN 300000
struct edge{int nx,t,w;}e[MN*+];
int n,h[MN+],en;
ll f[MN+],l[MN+],r[MN+];
vector<ll> v[MN+];
inline void ins(int x,int y,int w)
{
e[++en]=(edge){h[x],y,w};h[x]=en;
e[++en]=(edge){h[y],x,w};h[y]=en;
}
inline ll z(ll x){return x<?-x:x;}
void dp(int x,int fa)
{
if(x>n)return;
for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa)
{
dp(e[i].t,x);
f[x]+=f[e[i].t];
v[x].push_back(l[e[i].t]+e[i].w);
v[x].push_back(r[e[i].t]+e[i].w);
f[x]-=r[e[i].t]-l[e[i].t];
}
sort(v[x].begin(),v[x].end());
l[x]=v[x][v[x].size()/-];r[x]=v[x][v[x].size()/];
for(int i=;i<v[x].size();++i)f[x]+=z(l[x]-v[x][i]);
}
int main()
{
int m,i,x;
n=read();m=read();
for(i=;i<=n+m;++i)x=read(),ins(x,i,read());
dp(,);
cout<<f[]/;
}

正解:用f[i][j]表示子树i内所有叶节点到i距离为j的最小花费,则易知每个f[i]均为下凸函数且可以由各儿子的f合并得到,f[i]具有以下性质:1.f[i][0]=子树i内边权和;2.f[i][0]处函数斜率为负的子树内叶节点个数;3.j足够大时f[i][j]斜率为1。这样我们只要知道f[i][0]之后何时函数斜率增大即可表示这个函数,我们可以记下每个拐点,每个拐点表示在这个点函数斜率增加1(拐点可重),这样儿子的f相加直接把所有拐点合并即可。儿子的f并入父亲的f前先要考虑连到父亲的这条边对儿子的f的影响,分各类情况讨论,我们有:假设凸包H(x)最小值在L~R处取到,这条边长为w,新凸包为H’(x),则:x<=L时,H’(x)=H(x)+w;L<=x<=L+w时,H’(x)=H(L)+w-(x-L);L+w<=x<=R+w时,H’(x)=H(L);R+w<=x时,H’(x)=H(L)+(x-R)-w。即每次我们删掉拐点L和拐点R,并加入拐点L+w和R+w,然后删掉所有使斜率大于1的拐点即可。用可并堆维护拐点,最后把堆中元素全部取出计算答案,复杂度O(MlogM)。

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
inline int read()
{
int x;char c;
while((c=getchar())<''||c>'');
for(x=c-'';(c=getchar())>=''&&c<='';)x=(x<<)+(x<<)+c-'';
return x;
}
#define MN 600000
int fa[MN+],w[MN+],r[MN+],cnt;
ll p[MN*+];
struct heap
{
heap*l,*r;ll p;int d;
heap(ll p):p(p){l=r=;d=;}
friend inline int dis(heap*a){return a?a->d:;}
friend heap*merge(heap*a,heap*b)
{
if(!a)return b;if(!b)return a;
if(a->p<b->p)swap(a,b);
a->r=merge(a->r,b);
if(dis(a->l)<dis(a->r))swap(a->l,a->r);
a->d=dis(a->r)+;
return a;
}
}*rt[MN+];
int main()
{
int n,m,i,j;ll a,b,s=;
n=read();n+=m=read();
for(i=;i<=n;++i)++r[fa[i]=read()],s+=w[i]=read();
for(i=n;i>;--i)
{
if(!rt[i])rt[i]=new heap();
for(j=a=;j<=r[i];++j)
{
if(j<r[i])a=rt[i]->p;
else b=rt[i]->p;
rt[i]=merge(rt[i]->l,rt[i]->r);
}
rt[fa[i]]=merge(rt[fa[i]],merge(rt[i],merge(new heap(a+w[i]),new heap(b+w[i]))));
}
while(rt[])p[++cnt]=rt[]->p,rt[]=merge(rt[]->l,rt[]->r);
for(i=cnt;m;--m,--i)s-=m*(p[i]-p[i+]);
printf("%lld",s);
}

T3.gap

题目大意:交互题,有一个N个数的上升序列,不具体给出序列,仅支持一个操作:MinMax(l,r),会给你数值大小在[l,r]内的序列中元素的最大值和最小值,要求你求出序列中相邻元素的最大差。subtask1:每次MinMax的代价为1,使用的代价不得超过(N+1)/2;subtask2:每次MinMax的代价为[l,r]间元素个数加1,使用的代价不得超过3N。(N<=100,000,序列中元素在[0,1e18]内)

思路:我只会subtask1,先询问[0,1e18],得出最小值x最大值y,再询问[x+1,y-1],以此类推,就能(N+1)/2次询问得出整个序列,得分30/100。subtask2做法:先询问[0,1e18],得出最大最小值,则答案必然不小于(max-min)/(n-1),我们在[min+1,max-1]内每(max-min)/(n-1)分一块,显然块内不存在答案,答案只可能是每一块的最大值与下一块最小值的差分,于是每一块询问一次就可以了,简单的计算后知道这么做最大的代价是3N-1。

#include<cstdio>
#include<algorithm>
#include"gap.h"
#define ll long long
using namespace std;
#define MN 100000
#define INF 1e18
ll a[MN+];
ll find1(int n)
{
ll l=,r=INF;int i,j;
for(i=,j=n;i<=j;l=a[i++]+,r=a[j--]-)MinMax(l,r,a+i,a+j);
for(i=,r=;i<n;++i)r=max(r,a[i+]-a[i]);
return r;
}
ll findGap(int t,int n)
{
if(t==)return find1(n);
ll p,i;int cnt=;
MinMax(,INF,a+,a);
p=(a[]-a[]+n-)/(n-);
for(i=a[];i<a[]-;i+=p)
{
MinMax(i+,min(i+p,a[]-),a+cnt+,a+cnt+);
if(a[cnt+]>)if(++cnt,a[cnt+]!=a[cnt])++cnt;
}
a[++cnt]=a[];
for(i=;i<cnt;++i)p=max(p,a[i+]-a[i]);
return p;
}

APIO 2016的更多相关文章

  1. GDOI 2016 & APIO 2016 游记

    缓慢施工中...... UPD:APIO游记已烂尾......因为Cu滚粗+生病一直没心情写..过了几天就发现APIO的事都快忘光了...去看KPM的就可以啦 今年apio竟然没和gdoi撞...智障 ...

  2. [APIO 2016]Gap

    Description 题库链接 给你一个长度为 \(N\) 的单调递增序列 \(A\) .交互时允许你调用 MinMax(s, t, &mn, &mx) 函数,表示序列元素的值在 \ ...

  3. 【UOJ #205】【APIO 2016】Fireworks

    http://uoj.ac/problem/205 好神的题啊. dp[i][j]表示以i为根的子树调整成长度j需要的最小代价. 首先要观察到dp值是一个下凸壳. 因为从儿子合并到父亲时要把所有儿子的 ...

  4. 【UOJ #206】【APIO 2016】Gap

    http://uoj.ac/problem/206 对于T=1,直接从两端往中间跳可以遍历所有的点. 对于T=2,先求出最小值a和最大值b,由鸽巢原理,答案一定不小于\(\frac{b-a}{N-1} ...

  5. 【UOJ #204】【APIO 2016】Boat

    http://uoj.ac/problem/204 肯定要离散化的,先离散化出\(O(n)\)个取值区间. 设\(f(i,j)\)表示第\(i\)所学校派出的划艇数量在\(j\)区间中. \(f(i, ...

  6. Solution -「APIO 2016」「洛谷 P3643」划艇

    \(\mathcal{Description}\)   Link & 双倍经验.   给定 \(n\) 个区间 \([a_i,b_i)\)(注意原题是闭区间,这里只为方便后文描述),求 \(\ ...

  7. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  8. Be Better:遇见更好的自己-2016年记

    其实并不能找到好的词语来形容过去的一年,感觉就如此平淡的过了!没有了毕业的稚气,看事情淡了,少了一丝浮躁,多了一分认真.2016也许就是那句话-多读书,多看报,少吃零食多睡觉,而我更愿意说--Be B ...

  9. Connect() 2016 大会的主题 ---微软大法好

    文章首发于微信公众号"dotnet跨平台",欢迎关注,可以扫页面左面的二维码. 今年 Connect 大会的主题是 Big possibilities. Bold technolo ...

随机推荐

  1. 理解Python迭代对象、迭代器、生成器

    作者:zhijun liu链接:https://zhuanlan.zhihu.com/p/24376869来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 本文源自RQ作 ...

  2. eclipse下maven一些配置方法汇总

    随着eclipse的不同版本的变更:对maven插件的安装也有着不同的差异:之前也在一些版本的eclipse上安装成功地,但是最近又遇到了一些麻烦,故将这些方法记录下来: 大家都知道的最常用的一种方式 ...

  3. 【转】Python处理wave文件

    #本文PDF版下载 Python解析Wav文件并绘制波形的方法 #本文代码下载 Wav波形绘图代码 #本文实例音频文件night.wav下载 音频文件下载 (石进-夜的钢琴曲) 前言 在现在繁忙的生活 ...

  4. LeetCode & Q1-Two Sum-Easy

    Array Hash Table Question Given an array of integers, return indices of the two numbers such that th ...

  5. Python爬虫之urllib模块1

    Python爬虫之urllib模块1 本文来自网友投稿.作者PG,一个待毕业待就业二流大学生.玄魂工作室未对该文章内容做任何改变. 因为本人一直对推理悬疑比较感兴趣,所以这次爬取的网站也是平时看一些悬 ...

  6. BizTalk Server 2016配置 WCF SAP Adapter

    BizTalk Server 2016配置 WCF SAP Adapter 最近公司内部需要使用BizTalk与SAP 系统进行对接,虽然SAP/PI可以以发布WebService 的方式实现与外部系 ...

  7. 文本分类学习(三) 特征权重(TF/IDF)和特征提取

    上一篇中,主要说的就是词袋模型.回顾一下,在进行文本分类之前,我们需要把待分类文本先用词袋模型进行文本表示.首先是将训练集中的所有单词经过去停用词之后组合成一个词袋,或者叫做字典,实际上一个维度很大的 ...

  8. zuul入门(5)zuul 处理异常

    Object accessToken = request.getParameter("accessToken"); if(accessToken==null) { // 设置zuu ...

  9. SpringMvc(4-1)Spring MVC 中的 forward 和 redirect

    Spring MVC 中,我们在返回逻辑视图时,框架会通过 viewResolver 来解析得到具体的 View,然后向浏览器渲染.通过配置,我们配置某个 ViewResolver 如下: <b ...

  10. Android 学习资料入门到精通(PDF集合)共54本

    最近收集一些安卓入门到精通,包含游戏编程,网络编程,多媒体开发,需要学习朋友就下载保持下来,下载链接在最下面 下面是网盘内容 14天学会安卓开发_(完整版).pdf Android 4  游戏高级编程 ...