T1
按x值排序
遇到第二种牌插入 遇到第一种牌 查询<=y 的最小值 删除他
splay multiset
cys大佬说 multiset就是不去重的set,
#include <algorithm> #include <cstdio> #define N 100005 using namespace std; struct node { int x,y,opt; bool operator<(node a)const { if(opt!=a.opt&&x==a.x) return opt>a.opt; else return x<a.x; } }card[N<<1]; int n,ans,root,cn,siz[N],cnt[N],data[N],fa[N],ch[N][2]; inline void pushup(int rt) { int l=ch[rt][0],r=ch[rt][1]; siz[rt]=siz[l]+siz[r]+cnt[rt]; } inline void ins(int &rt,int x) { if(!rt) { rt=++cn; data[cn]=x; siz[cn]=cnt[cn]=1; return; } if(data[rt]==x) { cnt[rt]++; siz[rt]++; return; } if(x<data[rt]) { ins(ch[rt][0],x); fa[ch[rt][0]]=rt; pushup(rt); } else { ins(ch[rt][1],x); fa[ch[rt][1]]=rt; pushup(rt); } } int ask_pre(int rt,int x) { int p=rt,ret=0x7fffffff; while(p) { if(x<data[p]) p=ch[p][0]; else { ret=data[p]; p=ch[p][1]; } } return ret; } inline int son(int x) {return ch[fa[x]][1]==x;} void rotate(int x) { int y=fa[x],z=fa[y],b=son(x),c=son(y),a=ch[x][!b]; if(z) ch[z][c]=x; else root=x; fa[x]=z; if(a) fa[a]=y; ch[x][!b]=y;ch[y][b]=a; fa[y]=x; pushup(y);pushup(x); } void splay(int x,int i) { while(fa[x]!=i) { int y=fa[x],z=fa[y]; if(z==i) rotate(x); else { if(son(y)==son(x)) rotate(y),rotate(x); else rotate(x),rotate(x); } } } int getmn(int rt) { int ret=-1,p=rt; while(p) { ret=p; p=ch[p][0]; } return ret; } void del(int rt,int x) { if(data[rt]==x) { if(cnt[rt]>1) { cnt[rt]--; siz[rt]--; } else { splay(rt,0); int p=getmn(ch[rt][1]); if(p!=-1) { splay(p,rt); root=p;fa[p]=0; ch[p][0]=ch[rt][0]; fa[ch[rt][0]]=p; } else { root=ch[rt][0]; fa[ch[rt][0]]=0; } } return; } if(x<data[rt]) { del(ch[rt][0],x); pushup(rt); } else { del(ch[rt][1],x); pushup(rt); } } int main(int argc,char *argv[]) { freopen("water.in","r",stdin); freopen("water.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d%d",&card[i].x,&card[i].y),card[i].opt=1; for(int i=n+1;i<=n<<1;++i) scanf("%d%d",&card[i].x,&card[i].y),card[i].opt=2; sort(card+1,card+1+n*2); for(int i=1;i<=n<<1;++i) { if(card[i].opt==2) ins(root,card[i].y); else { if(!cn) continue; int v=ask_pre(root,card[i].y); if(v==0x7fffffff) continue; ans++; del(root,v); } } printf("%d\n",ans); fclose(stdin); fclose(stdout); return 0; }
splay
#include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> #include <set> using namespace std; int n; multiset <int> s; struct node {int x,y;} a[100005],b[100005]; int cmp(node i,node j) {return i.x<j.x;} int main() { freopen("water.in","r",stdin); freopen("water.out","w",stdout); int T; T=1; while(T--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d%d",&a[i].x,&a[i].y); for(int i=0;i<n;i++) scanf("%d%d",&b[i].x,&b[i].y); sort(a,a+n,cmp); sort(b,b+n,cmp); s.clear(); int k=0,ans=0; for(int i=0;i<n;i++) { while(a[i].x>=b[k].x&&k<n) { s.insert(b[k].y); k++; } if(s.empty())continue; multiset<int>::iterator it=s.upper_bound(a[i].y); if (it==s.begin()) continue; it--; ans++; s.erase(it); } printf("%d\n",ans); } return 0; }
multiset
T2
最少需要 log(n)/log(2) 个
dp[j][k] 表示 金币和是 j 最大金币是k 的方案总数
枚举下一枚金币是什么
#include <cstdio> #include <cmath> #define N 1005 inline int min(int a,int b) {return a>b?b:a;} int n,s,ans,f[N][N],dp[N][N]; int main(int argc,char *argv[]) { freopen("dream.in","r",stdin); freopen("dream.out","w",stdout); scanf("%d",&n); s=log2(n)+1; f[1][1]=1; for(int i=1;i<s;++i) { for(int j=1;j<=n;++j) for(int k=1;k<=n;++k) if(f[j][k]) for(int l=k+1;l<=j+1;++l) dp[min(n,j+l)][l]+=f[j][k]; for(int j=1;j<=n;++j) for(int k=1;k<=n;++k) f[j][k]=dp[j][k],dp[j][k]=0; } for(int i=1;i<=n;++i) ans+=f[n][i]; printf("%d %d\n",s,ans); fclose(stdin); fclose(stdout); return 0; }
T3
dp[i][j] 表示 1~i 切了j刀的最优解
dp[i][j]=min{dp[k][j-1]+sum(k+1,i)}
从大到小 枚举k 更新sum
复杂度 20*N^2
固定j,随着i的增大,k不会减少
1d1d动态规划优化
20*n^2的简单dp -> 在固定j的情况下 随着i的增大,k不降 -> 分治求dp值
#include <cstdio> #define N 100005 typedef long long LL; int n,k,L,R,a[N],s[N]; LL sum,f[N],g[N]; void update(int x,int type) { if(type==1) sum+=s[a[x]],++s[a[x]]; else --s[a[x]],sum-=s[a[x]]; } void move(int l,int r) { while(l<L) update(--L,1); while(r>R) update(++R,1); while(l>L) update(L++,0); while(r<R) update(R--,0); } void work(int l,int r,int fl,int fr) { if(fl>fr) return; int mid=(fl+fr)>>1,mi; LL mx=1LL<<60; for(int i=l;i<mid&&i<=r;++i) { move(i+1,mid); if(mx>f[i]+sum) mx=f[i]+sum,mi=i; } g[mid]=mx; work(l,mi,fl,mid-1); work(mi,r,mid+1,fr); } int main(int argc,char *argv[]) { freopen("dp.in","r",stdin); freopen("dp.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1;i<=n;++i) scanf("%d",&a[i]); f[0]=0; for(int i=1;i<=n;++i) f[i]=1LL<<60; while(k--) { L=1,R=0,sum=0; for(int i=1;i<=n;++i) s[i]=0; work(0,n-1,1,n); for(int i=0;i<=n;++i) f[i]=g[i],g[i]=0; } printf("%I64d\n",f[n]); fclose(stdin); fclose(stdout); return 0; }
时间: 2024-10-08 21:22:47