标签:
看到多操作一般都是数据结构题,阀盖splay裸题,不赘述了
#include <bits/stdc++.h> using namespace std; const int MAXN=2e5+100; int lim; struct SplayTree { int sz[MAXN]; int ch[MAXN][2]; int pre[MAXN]; int rt,top; inline void up(int x) { sz[x]=cnt[x]+sz[ ch[x][0] ]+sz[ ch[x][1] ]; } inline void Rotate(int x,int f) { int y=pre[x]; ch[y][!f]=ch[x][f]; pre[ ch[x][f] ]=y; pre[x]=pre[y]; if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1]==y ] =x; ch[x][f]=y; pre[y]=x; up(y); } inline void Splay(int x,int goal) {//将x旋转到goal的下面 while(pre[x] != goal) { if(pre[pre[x]]==goal) Rotate(x ,ch[pre[x]][0]==x); else { int y=pre[x],z=pre[y]; int f=(ch[z][0]==y); if(ch[y][f]==x) Rotate(x,!f),Rotate(x,f); else Rotate(y,f),Rotate(x,f); } } up(x); if(goal==0) rt=x; } inline void RTO(int k,int goal) {//将第k位数旋转到goal的下面 int x=rt; while(sz[ ch[x][0] ] != k-1) { if(k < sz[ ch[x][0] ]+1) x=ch[x][0]; else { k-=(sz[ ch[x][0] ]+1); x=ch[x][1]; } } Splay(x,goal); } inline void Newnode(int &x,int c) { x=++top; ch[x][0]=ch[x][1]=pre[x]=0; sz[x]=1; cnt[x]=1; val[x]=c; } inline void init() { sum=ch[0][0]=ch[0][1]=pre[0]=sz[0]=0; rt=top=0; cnt[0]=0; } inline void Insert(int &x,int key,int f) { if(!x) { Newnode(x,key); pre[x]=f; Splay(x,0); return ; } if(key==val[x]) { cnt[x]++; sz[x]++; Splay(x,0); return ; }else if(key<val[x]) { Insert(ch[x][0],key,x); } else { Insert(ch[x][1],key,x); } up(x); } void del(int &x,int f) { if(!x) return ; if(val[x]>=lim) { del(ch[x][0],x); } else { sum+=sz[ch[x][0]]+cnt[x]; x=ch[x][1]; pre[x]=f; if(f==0) rt=x; del(x,f); } if(x) up(x); } inline void update() { del(rt,0); } inline int find_kth(int x,int k) { if(k<sz[ch[x][0]]+1) { return find_kth(ch[x][0],k); }else if(k > sz[ ch[x][0] ]+cnt[x] ) return find_kth(ch[x][1],k-sz[ch[x][0]]-cnt[x]); else { Splay(x,0); return val[x]; } } int cnt[MAXN]; int val[MAXN]; int sum; }spt; int main() { int n,m; char op[5]; scanf("%d%d",&n,&m); int w=0; spt.init(); while(n--) { int k; scanf("%s%d",op,&k); if(op[0]=='I') { if(k<m) { continue; } spt.Insert(spt.rt,k-w,0); } else if(op[0]=='A') { w+=k; } else if(op[0]=='S') { w-=k; lim=m-w; spt.update(); } else { int sz=spt.sz[spt.rt]; if(k>sz) printf("-1\n"); else printf("%d\n",spt.find_kth(spt.rt,sz-k+1)+w); } } printf("%d\n",spt.sum); return 0; }
这是一道不太明显的动态规划题。
对于两条横向道路A,B,考虑四种不同的方向,然后纵向道路需要满足怎样的方向才可以满足题目要求,预处理出来。
这样,问题就转换成:寻找一种最小花费的纵向道路方案,使得其满足一系列类似这样的要求:在某个区间内至少存在一种某方向的纵向街道。然后就一目了然了。
#include <bits/stdc++.h> using namespace std; const int maxn=100+10,maxl=200+10; const int INF=0x3f3f3f3f; int n,m,K,r[3],rr[3][maxn],ll[3][maxn],costm[maxn][3],costn[maxn][3]; int sm[maxn],sn[maxn],vm[maxn],vn[maxn],f[maxn][maxl][maxl]; char s[maxn]; struct req { int x1,x2,y1,y2;} a[maxn]; struct inter { int l,r;} in[3][maxl]; inline bool cmp(const inter &a,const inter &b) { return a.l<b.l || (a.l==b.l && a.r<b.r);} void maintain() { sort(in[0]+1,in[0]+r[0]+1,cmp); sort(in[1]+1,in[1]+r[1]+1,cmp); for(int q=0;q<2;++q) { for(int i=1;i<=n;++i) { int j=1;ll[q][i]=1; for(;j<=r[q];++j) if(in[q][j].l>i) break; else if(in[q][j].r<i) ll[q][i]=j+1; rr[q][i]=j; } } } void add(int p,int L,int R) { if(L>R) swap(L,R); for(int i=1;i<=r[p];++i) if(L<=in[p][i].l && in[p][i].r<=R) return; in[p][++r[p]].l=L,in[p][r[p]].r=R; } bool prepare(int s) { memset(rr,0 ,sizeof rr); memset(ll,0,sizeof ll); r[0]=0,r[1]=0; for(int i=1;i<=K;++i) { int x1=a[i].x1,y1=a[i].y1,x2=a[i].x2,y2=a[i].y2; int p=(x1<x2),q=(y1<y2); if(x1!=x2 && y1!=y2) { if(((s >> (x1-1)) & 1)==q && ((s >> (x2-1)) & 1)==q) add(p,y1,y2); else if(((s >> (x1-1)) & 1)==q) add(p,y2,y2); else if(((s >> (x2-1)) & 1)==q) add(p,y1,y1); else { int t=0,fr=min(x1,x2)+1,en=max(x1,x2); for(int j=fr;j<en;++j) if(((s >> (j-1)) & 1)==q) t=1; if(!t) return 0; add(p,y1,y1);add(p,y2,y2); } } else if(x1==x2 && y1!=y2 && ((s >> (x1-1)) & 1) != q) return 0; else if(x1!=x2 && y1==y2) add(p,y1,y2); } maintain(); return 1; } int dp() { memset(f,0x7,sizeof f); f[1][1][1]=0; for(int i=1;i<=n;++i) for(int j=ll[0][i];j<=rr[0][i];++j) for(int k=ll[1][i];k<=rr[1][i];++k) if(f[i][j][k]<INF) { if(f[i+1][rr[0][i]][k]>f[i][j][k]+costn[i][0]) f[i+1][rr[0][i]][k]=f[i][j][k]+costn[i][0]; if(f[i+1][j][rr[1][i]]>f[i][j][k]+costn[i][1]) f[i+1][j][rr[1][i]]=f[i][j][k]+costn[i][1]; } return f[n+1][r[0]+1][r[1]+1]; } int main() { scanf("%d%d",&m,&n); scanf("%s",s); for(int i=1;i<=m;++i) sm[i]=(s[i-1]=='E'); scanf("%s",s); for(int i=1;i<=n;++i) sn[i]=(s[i-1]=='S'); for(int i=1;i<=m;++i) { scanf("%d",vm+i); costm[i][sm[i]]=0,costm[i][1-sm[i]]=vm[i]; } for(int i=1;i<=n;++i) { scanf("%d",vn+i); costn[i][sn[i]]=0,costn[i][1-sn[i]]=vn[i]; } scanf("%d",&K); for(int i=1;i<=K;++i) scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2); int tot=(1<<m),ans=INF; for(int i=0;i<tot;++i) { int t=0; for(int j=1;j<=m;++j) t += costm[j][(i>>(j-1))&1]; if(prepare(i)) { t += dp(); ans=min(ans,t); } } if(ans<INF) { printf("possible\n"); printf("%d\n",ans); } else printf("impossible\n"); return 0; }
一些在不同高度的伞(线段)可以左右移动,给定初始方向和速度。求开始下雨到T时间有多少雨水落在了地面上
可以用Simpson自适应公式来做,但显然那样会比较麻烦。
我们用分段求面积的方法来做,这利用了所有图形都是平行四边形的特殊性。
将坐标轴反过来,t为x轴,位置为y轴,然后找到所有线段的交点(图自己画一下吧)
由图可知,所有的交点将图分了好多部分,每一部分的面积是连续变化的,用公式area(a,b)=(s(b)+s(a))*(b-a)/2计算,s(a)指直线x=a在图形上截得的总面积。将所有区间面积加起来。
#include <bits/stdc++.h> using namespace std; const int maxn=301,maxm=5010; const double eps=1e-8; int n,m,w,T,V,ind; double a[maxm]; struct line { double x,y,len,k,L,R; } L[maxm]; struct inter { double l,r; } c[maxn]; bool cmp(const inter &a,const inter &b) { return a.l<b.l || (a.l == b.l && a.r<b.r); } double f(double x) { double s=0;int p=0; for(int i=1;i<=m;i++) if(L[i].L<=x && x<=L[i].R) { c[++p].l=(x-L[i].x)*L[i].k+L[i].y; c[p].r=c[p].l+L[i].len; } if(!p) return 0; sort(c+1,c+p+1,cmp); double l=c[1].l,r=c[1].r; for(int i=2;i<=p;i++) if(c[i].l>r) { s+=r-l; l=c[i].l; r=c[i].r; } else r=max(c[i].r,r); s+=(r-l); return s; } double area() { double s=0; for(int i=2;i<=ind;i++) s += (f(a[i])+f(a[i-1]))*(a[i]-a[i-1])/2; return s; } void check(double x,double y,double len,double v,double t) { L[++m].L=x,L[m].R=x+t,L[m].k=v; L[m].x=x,L[m].y=y,L[m].len=len; double l=y+t*v,r=y+len+t*v; if(r>w+eps) { L[m].R=x+(w-len-y)/v; check(L[m].R,w-len,len,-v,t-(w-len-y)/v); } else if(l<-eps) { L[m].R=x-y/v; check(L[m].R,0,len,-v,t+y/v); } else a[++ind]=x+t; a[++ind]=x; } bool cross(int i,int j) { return L[i].R>=L[j].L && L[i].L<=L[j].R && fabs(L[i].k-L[j].k)>eps; } void get_p(int i,int j) { double x1=L[i].x,x2=L[j].x,y1=L[i].y,y2=L[j].y; double k1=L[i].k,k2=L[j].k,L1=L[i].L,L2=L[j].L; double R1=L[i].R,R2=L[j].R,len1=L[i].len,len2=L[j].len; double x=(y2-y1+x1*k1-x2*k2)/(k1-k2); if(L1<=x && x<=R1 && L2<=x && x<=R2) a[++ind]=x; x=(y2+len2-y1+x1*k1-x2*k2)/(k1-k2); if(L1<=x && x<=R1 && L2<=x && x<=R2) a[++ind]=x; x=(y2-len1-y1+x1*k1-x2*k2)/(k1-k2); if(L1<=x && x<=R1 && L2<=x && x<=R2) a[++ind]=x; x=(y2+len2-len1-y1+x1*k1-x2*k2)/(k1-k2); if(L1<=x && x<=R1 && L2<=x && x<=R2) a[++ind]=x; } int main() { scanf("%d%d%d%d",&n,&w,&T,&V); for(int i=1;i<=n;i++) { double x,l,v; scanf("%lf%lf%lf",&x,&l,&v); if(x || l!=w) check(0,x,l,v,(double)T); else { printf("0.00"); return 0; }; } for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) if(i!=j && cross(i,j)) get_p(i,j); sort(a+1,a+ind+1); printf("%.2lf\n",(T*w-area())*V); return 0; }
小屋东西长为100,东西墙均平行于y轴,南北墙分别是斜率为k1和k2的直线(k1和k2为正实数)。南北墙的墙角处有很多块草坪,每块草坪都是一个矩形,矩形的每条边都平行于坐标轴。相邻两块草坪的接触点恰好在墙上,接触点的横坐标必须是1到99的整数。在北墙角要有m块草坪,在南墙角要有n块草坪,并约定m≤n。如果记北墙和南墙的分点集合分别为X1,X2,则应满足X1是X2的约数,即北墙的任何一个分点一定是南墙的分点。同时草坪的占地总面积最小
首先想到贪心,但是只会有40分,这是一道动态规划题,比较难想
dp[i][j][k]表示长度为k,北边有i个草坪,南边有j个草坪时的最小面积
因为北边的草坪数少于南边,所以按北边来递推,这样也可不用考虑状态是否合法
预处理s[i][j]表示距离为i时,南边有j块草坪的最小面积
dp[i][j][k]=min(dp[i][j][k],dp[i-1][j‘][k‘]+kb*(k-k‘)^2+s[k-k‘][j-j‘])
#include <bits/stdc++.h> using namespace std; const int MAXN=100+5; const double INF=0x3f3f3f3f; double kb,kn,g[MAXN][MAXN],dp[MAXN][MAXN][MAXN]; int m,n; int main() { scanf("%lf%lf%d%d",&kb,&kn,&m,&n); for(int i=0;i<MAXN;i++) for(int j=0;j<MAXN;j++) { for(int k=0;k<MAXN;k++) dp[i][j][k]=INF; g[i][j]=INF; } g[0][0] =0; for(int i=1;i<=100;i++) for(int j=1;j<=i;j++) { for(int k=j-1;k<i;k++) g[i][j]=min(g[i][j],g[k][j-1]+(i-k)*(i-k)*kn); } dp[0][0][0]=0; for(int k=1;k<=100;k++) for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) for(int kk=i-1;kk<k;kk++) for(int jj=i-1;jj<j;jj++) dp[i][j][k]=min(dp[i][j][k],dp[i-1][jj][kk]+(k-kk)*(k-kk)*kb+g[k-kk][j-jj]); printf("%.1lf",dp[m][n][100]); return 0; }
标签:
原文地址:http://blog.csdn.net/qq_25471829/article/details/46228333