您的位置:首页 > 其它

BZOJ3711: [PA2014]Druzyny

2017-12-15 09:26 393 查看
orz

考虑dp,f[i]表示1~i至多分成几段,g[i]表示1~i分成f[i]段的方案数

转移的时候将c[i],d[i]的限制分开考虑

对于d[i]的限制,不难发现他有单调性,可以预处理L[i]表示L[i]~i-1的j满足d[i]的限制可以由j转移到i

然后考虑c[i]的限制,他没有单调性,于是对c进行分治

如果我们在处理[l,r]这一个区间,找出[l+1,r]内c的最大值的位置k,那么k左边的j转移到i时,c值都是确定的c[k],接下来就是根据L[i],i,j的位置关系分情况讨论

先递归处理[l,k-1]的dp值,然后考虑[l,k-1]的j到[k,r]的i的转移

1:L[i]<=l,max(l+c[k],k)<=i<=min(k−1+c[k],r)

这种情况下随着i的右移,能贡献到i的j的集合每次增加一个元素,L[i]<=l的区间可以二分求O(logn),先用线段树查对左端点的贡献,然后i右移时可以O(1)更新,复杂度是O(较小的区间)

2:L[i]<=l,k−1+c[k]<=i<=r

可以直接线段树上区间更新i,复杂度O(logn)

3:l<L[i]<=k−1,k<=i<=r,二分求出i的取值范围,枚举i线段树查更新,因为分治的区间是不相交的,也就是说l<L[i]<=k−1对每个i只有一个这样的区间,因此这部分总复杂度是O(nlogn)的

因为总共O(n)个区间,总复杂度O(nlogn)

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
char c; int f=1;
while(!((c=getchar())>='0'&&c<='9')) if(c=='-') f=-1;
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
if(f==-1) x=-x;
}
const int maxn = 1010000;
const int mod = 1000000007;
void add(int &a,int b){a+=b;if(a>=mod)a-=mod;}

int n;
int c[maxn],d[maxn],L[maxn];
int t[maxn],ti[maxn],tp;

struct node{int x,c;}f[maxn],zero;
void upd(node &a,const node &b)
{
if(a.x<b.x) a.x=b.x,a.c=0;
if(a.x==b.x) add(a.c,b.c);
}

struct segment{int ci;node f,flag;}seg[maxn<<2];
void build(const int x,const int l,const int r)
{
seg[x].f=seg[x].flag=zero;
if(l==r) { seg[x].ci=l; return; }
int mid=l+r>>1,lc=x<<1,rc=lc|1;
build(lc,l,mid); build(rc,mid+1,r);
seg[x].ci=c[seg[lc].ci]>=c[seg[rc].ci]?seg[lc].ci:seg[rc].ci;
}
node re;
int loc;
void updp(const int x,const int l,const int r)
{
upd(seg[x].f,f[loc]);
if(l==r) { seg[x].f=f[l]; return; }
int mid=l+r>>1,lc=x<<1,rc=lc|1;
if(loc<=mid) updp(lc,l,mid);
else updp(rc,mid+1,r);
}
void queryp(const int x,const int l,const int r)
{
upd(re,seg[x].flag);
if(l==r)return;
int mid=l+r>>1;
if(loc<=mid) queryp(x<<1,l,mid);
else queryp(x<<1|1,mid+1,r);
}
node fl;
int lx,rx;
void cover(const int x,const int l,const int r)
{
if(rx<l||r<lx) return;
if(lx<=l&&r<=rx) { upd(seg[x].flag,fl);return; }
int mid=l+r>>1;
cover(x<<1,l,mid); cover(x<<1|1,mid+1,r);
}
void queryf(const int x,const int l,const int r)
{
if(rx<l||r<lx) return;
if(lx<=l&&r<=rx) { upd(re,seg[x].f);return; }
int mid=l+r>>1;
queryf(x<<1,l,mid); queryf(x<<1|1,mid+1,r);
}
int queryc(const int x,const int l,const int r)
{
if(rx<l||r<lx) return 0;
if(lx<=l&&r<=rx) return seg[x].ci;
int mid=l+r>>1;
int la=queryc(x<<1,l,mid),ra=queryc(x<<1|1,mid+1,r);
if(c[la]==c[ra]) return la-l>r-ra?la:ra;
return c[la]>c[ra]?la:ra;
}

void solve(const int l,const int r)
{
if(l==r)
{
re=zero; loc=l; queryp(1,0,n);
upd(f[l],re);
loc=l; updp(1,0,n);
return;
}
lx=l+1,rx=r; int k=queryc(1,0,n),cc=c[k];
solve(l,k-1);

int pl=k,pr=r;
while(pl<=pr)
{
int mid=pl+pr>>1;
if(L[mid]<=l) pl=mid+1;
else pr=mid-1;
}pl--;
if(pl>=k)
{
int u=min(pl,k-1+cc);
re=zero; lx=l,rx=max(k-cc,l); queryf(1,0,n);
for(int j=max(k,l+cc);j<=u;j++)
{
if(re.x>=0) re.x++,upd(f[j],re),re.x--;
if(j<u&&j+1-cc>=l) upd(re,f[j+1-cc]);
}
if(u<pl)
{
lx=u+1,rx=pl; fl=re;
if(fl.x>=0) fl.x++,cover(1,0,n);
}
}
int tmp=++pl; pr=r;
while(pl<=pr)
{
int mid=pl+pr>>1;
if(L[mid]<=k-1) pl=mid+1;
else pr=mid-1;
}pl--;
if(L[pl]>l&&L[pl]<k)
{
pr=pl; pl=tmp;
for(int j=pl;j<=pr;j++)
{
lx=L[j],rx=min(k-1,j-cc);
if(lx<=rx)
{
re=zero; queryf(1,0,n);
if(re.x>=0) re.x++,upd(f[j],re),re.x--;
}
}
}

solve(k,r);
}

int main()
{
zero=(node){-1,0};

read(n);
for(int i=1;i<=n;i++) read(c[i]),read(d[i]);

tp=0; int l=1;
for(int i=1;i<=n;i++)
{
if(t[tp]>=d[i])
{
t[tp]=d[i];
while(tp>1&&t[tp-1]>=t[tp]) t[--tp]=t[tp+1];
}
else t[++tp]=d[i],ti[tp]=i;
int j=L[i-1]; if(l>tp) l=tp;
while(i-j>t[l])
{
j++; if(l<tp&&j+1>=ti[l+1]) l++;
}
L[i]=j;
}
f[0]=(node){0,1}; for(int i=1;i<=n;i++) f[i]=zero;
build(1,0,n);

solve(0,n);
//for(int i=1;i<=n;i++) printf("%d %d\n",f[i].x,f[i].c);
if(f
.x==-1) puts("NIE");
else printf("%d %d\n",f
.x,f
.c);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: