「BZOJ3688」折線統計 題解
阿新 • • 發佈:2021-11-06
熬煞我的97行程式碼
DP分析
· 狀態:使用三元組 \(f(i,j,false/true)\) 表示在前 \(i\) 個點中,選取了 \(j\) 條線段,其中最後一條線段是下降 \((false)\) 或上升 \((true)\) 的方案數;
· 目標:$$f(n,k,false)+f(n,k,true)$$
· 狀態轉移方程
· 當然逃不過樹狀陣列優化
具體實現
將 \(a\) 陣列沿X軸排序,並對Y軸進行離散化。
struct XOY{
int x,y;
friend bool operator<(XOY fir,XOY sec){
return fir.x<sec.x;
}
}a[maxn];
出於未知的幻想,鄙人先使用了二叉搜尋樹對 \(a.y\) 離散化:
struct BSTree{ struct BSTree_node{ int num; bool vis; int l,r; }b[maxn]; int tot,a_tot; inline void f(){ tot=1;//最容易忘掉的頭疼東西 a_tot=0; } inline void push(int k,int x){//存樹 if(!b[k].vis){ b[k].num=x; b[k].vis=true; return ; }else if(x<=b[k].num){//大的相等的存左兒子 if(!b[k].l)b[k].l=++tot;//沒兒子,新增節點,到最後b的順序會驚喜地等於a.y的順序 push(b[k].l,x); }else if(x>b[k].num){//小的存右兒子 if(!b[k].r)b[k].r=++tot; push(b[k].r,x); } } inline void disc(int k){//離散 if(!b[k].vis)return ; disc(b[k].l); a[k].y=++a_tot; disc(b[k].r); } }bst;
main:
bst.f();
for(int i=1;i<=n;i++){
a[i].x=read();a[i].y=read();
bst.push(1,a[i].y);
}
bst.disc(1);
sort(a+1,a+1+n);
使用樹狀陣列 \(t(j,false/true)\) 省略第一維:
struct BITree{ int c[maxn]; inline int lowbit(int x){return x&(-x);} inline void add(int x,int val){ val=(val%mod+mod)%mod;//這個特別重要,下文解釋 while(x<=n){ c[x]=(c[x]+val)%mod; x+=lowbit(x); } } inline int query(int x){ int ret=0; while(x){ ret=(c[x]+ret)%mod; x-=lowbit(x); } return ret; } }t[11][2];
main:
for(int i=1;i<=n;i++){
t[0][0].add(a[i].y,1);
t[0][1].add(a[i].y,1);
for(int j=1;j<=k;j++){
int tmpa=t[j][0].query(n)-t[j][0].query(a[i].y);
int tmpb=t[j-1][1].query(n)-t[j-1][1].query(a[i].y);
int tmpc=t[j][1].query(a[i].y-1)+t[j-1][0].query(a[i].y-1);
t[j][0].add(a[i].y,tmpa+tmpb);
t[j][1].add(a[i].y,tmpc);
}
}
有一點差點把我卡惑了:
val=(val%mod+mod)%mod;
這個語句在 BITree.add(int x,int val)
中,需要注意的是,用 tmpa+tmpb
傳導的 val
中有減法,而 tmpa
和 tmpb
獲取的值本身是進行過 mod
,所以不可以直接 val%=mod
;
舉個例子:
比如 x=21 , y=19 , mod=5
那麼 val
應該為 (21-19)% 5 = 2;
而事實上,x在 BITree 中取模後值為 1,y值為 4
此時 val
應該為 (1-4+5)% 5 = 2;而不是(1-4)% 5 = 2;
完整 AC Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=50010;
const int mod=1e5+7;
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<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,k;
struct BITree{
int c[maxn];
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int val){
val=(val%mod+mod)%mod;
while(x<=n){
c[x]=(c[x]+val)%mod;
x+=lowbit(x);
}
}
inline int query(int x){
int ret=0;
while(x){
ret=(c[x]+ret)%mod;
x-=lowbit(x);
}
return ret;
}
}t[11][2];
struct XOY{
int x,y;
friend bool operator<(XOY fir,XOY sec){
return fir.x<sec.x;
}
}a[maxn];
struct BSTree{
struct BSTree_node{
int num;
bool vis;
int l,r;
}b[maxn];
int tot,a_tot;
inline void f(){
tot=1;
a_tot=0;
}
inline void push(int k,int x){
if(!b[k].vis){
b[k].num=x;
b[k].vis=true;
return ;
}else if(x<=b[k].num){
if(!b[k].l)b[k].l=++tot;
push(b[k].l,x);
}else if(x>b[k].num){
if(!b[k].r)b[k].r=++tot;
push(b[k].r,x);
}
}
inline void disc(int k){
if(!b[k].vis)return ;
disc(b[k].l);
a[k].y=++a_tot;
disc(b[k].r);
}
}bst;
int main(){
n=read();k=read();
bst.f();
for(int i=1;i<=n;i++){
a[i].x=read();a[i].y=read();
bst.push(1,a[i].y);
}
bst.disc(1);
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
t[0][0].add(a[i].y,1);
t[0][1].add(a[i].y,1);
for(int j=1;j<=k;j++){
int tmpa=t[j][0].query(n)-t[j][0].query(a[i].y);
int tmpb=t[j-1][1].query(n)-t[j-1][1].query(a[i].y);
int tmpc=t[j][1].query(a[i].y-1)+t[j-1][0].query(a[i].y-1);
t[j][0].add(a[i].y,tmpa+tmpb);
t[j][1].add(a[i].y,tmpc);
}
}
printf("%d\n",(t[k][0].query(n)+t[k][1].query(n))%mod);
return 0;
}
97行萬歲