十一模拟赛
bzoj1826bzoj1528
Jasio 是一个三岁的小男孩,他最喜欢玩玩具了,他有n 个不同的玩具,它们都被放在了很高的架子上所以Jasio 拿不到它们. 为了让他的房间有足够的空间,在任何时刻地板上都不会有超过k 个玩具. Jasio 在地板上玩玩具. Jasio’的妈妈则在房间里陪他的儿子. 当Jasio 想玩地板上的其他玩具时,他会自己去拿,如果他想玩的玩具在架子上,他的妈妈则会帮他去拿,当她拿玩具的时候,顺便也会将一个地板上的玩具放上架子使得地板上有足够的空间. 他的妈妈很清楚自己的孩子所以他能够预料到Jasio 想玩些什么玩具. 所以她想尽量的使自己去架子上拿玩具的次数尽量的少,应该怎么安排放玩具的顺序呢?
bzoj1826需要离散化
记录下每个玩具下次出现的位置,每次要删的话选一个最远的删掉
用堆维护这一过程
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<vector> #include<map> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } struct p { int pos,val; bool operator < (const p &a)const { return pos < a.pos; } }c[500010]; priority_queue<p> q; bool inq[500010]; int hash[1000010]; int n,k,p,ans; int main() { freopen("book.in","r",stdin); freopen("book.out","w",stdout); n=read();k=read();p=read(); for(int i=1;i<=p;i++) { c[i].val=read(); hash[c[i].val]=i; } for(int i=p;i>=1;i--) { if(hash[c[i].val]!=i)c[i].pos=hash[c[i].val]; else c[i].pos=2147483233; hash[c[i].val]=i; } for(int i=1;i<=k;i++) { if(!inq[c[i].val]) { q.push(c[i]); inq[c[i].val]=1; ans++; //cout<<i<<" "<<c[i].val<<" "<<endl; //system("pause"); } else { q.push(c[i]); k++; } } for(int i=k;i<=p;i++) { if(inq[c[i].val]){q.push(c[i]);continue;} if(!inq[c[i].val]) { ans++; inq[c[i].val]=1; inq[q.top().val]=0; q.pop(); q.push(c[i]); //cout<<i<<" "<<c[i].val<<" "<<endl; //system("pause"); } } printf("%d",ans); }
100分
poj2948
dp 打一个横着的前缀和和一个竖着的前缀和
每个状态可以由它左边和上面转移过来
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; int dp[505][505]; int x[505][505],y[505][505]; int n,m; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } int main() { freopen("ore.in","r",stdin); freopen("ore.out","w",stdout); while(scanf("%d%d",&n,&m)) { if(!n&&!m) return 0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { x[i][j]=read(); x[i][j]+=x[i][j-1]; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { y[i][j]=read(); y[i][j]+=y[i-1][j]; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(i==1) { if(j==1) dp[i][j]=max(y[i][j],x[i][j]); else dp[i][j]=max(dp[i][j-1]+y[i][j],x[i][j]); } else { if(j==1) dp[i][j]=max(y[i][j],dp[i-1][j]+x[i][j]); else dp[i][j]=max(dp[i][j-1]+y[i][j],dp[i-1][j]+x[i][j]); } } printf("%d\n",dp[n][m]); } }
100分...顺便 这是三道题中最水的 所以以后一定要看清题意zzzz
poj2828
线段树 由题意可知最后一个人入队时的位置就是他最终位置
所以逆序插点 线段树维护一下L~R的线段树
100分 今天AK
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<vector> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,k; int M; int tr[200010*4],p[200010],v[200010],ans[200010*4]; inline void change(int k){for(int i=k+M;i;i>>=1)tr[i]++;} inline void insert(int x,int y) { int i=1; while(i<M) { tr[i]--;i<<=1; if(tr[i]<x)x-=tr[i],i|=1; } tr[i]--,ans[i-M]=y; } int main() { freopen("queue.in","r",stdin); freopen("queue.out","w",stdout); while(~scanf("%d",&n)) { memset(p,0,sizeof(p)); memset(v,0,sizeof(v)); for(M=1;M<n;M<<=1); for(int i=0;i<n;i++)change(i); for(int i=0;i<n;i++)scanf("%d%d",p+i,v+i); for(int i=n-1;i>=0;i--)insert(p[i]+1,v[i]); for(int i=0;i<n;i++)printf("%d ",ans[i]); printf("\n"); } return 0; }
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<queue> #include<vector> #include<set> #include<stack> #define inf 2147483611 #define ll long long #define MAXN 201010 using namespace std; inline int read() { int x=0,f=1; char ch;ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } struct data { int w,l,r; }tr[MAXN*3]; int pos[MAXN],val[MAXN],n,ans[MAXN],now; void build(int k,int l,int r) { tr[k].l=l,tr[k].r=r,tr[k].w=r-l+1; if(l==r) return ; int m=(l+r)>>1; build(k<<1,l,m);build(k<<1|1,m+1,r); return ; } void update(int k,int p) { tr[k].w--; int l=tr[k].l,r=tr[k].r; if(l==r) {now=l;return ;} if(tr[k<<1].w>=p) update(k<<1,p); else { p-=tr[k<<1].w; update(k<<1|1,p); } } int main() { while(scanf("%d",&n)!=EOF) { build(1,1,n); for(int i=1;i<=n;i++) pos[i]=read(),val[i]=read(); for(int i=n;i>=1;i--) {update(1,pos[i]+1);ans[now]=val[i];} for(int i=1;i<=n;i++) printf("%d ",ans[i]); printf("\n"); } }
两个人 一个墙 一面镜子 墙和镜子不相交 问两个人能不能相互看见
计算几何瞎暴力系列
细节:要翻折两遍防止墙挡不住翻折之后但挡得住翻折之前
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<cstring> using namespace std; //计算几何瞎暴力 const double eps=1e-9; struct poi { double x,y; }; poi h,q,hs,wt,ms,mt; double mult(poi a, poi b, poi c){return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);} bool jiao(poi aa, poi bb, poi cc, poi dd) { if ( max(aa.x, bb.x)<min(cc.x, dd.x) )return false; if ( max(aa.y, bb.y)<min(cc.y, dd.y) )return false; if ( max(cc.x, dd.x)<min(aa.x, bb.x) )return false; if ( max(cc.y, dd.y)<min(aa.y, bb.y) )return false; if ( mult(cc, bb, aa)*mult(bb, dd, aa)<0 )return false; if ( mult(aa, dd, cc)*mult(dd, bb, cc)<0 )return false; return true; } double k; int main() { freopen("b.in","r",stdin); freopen("b.out","w",stdout); scanf("%lf%lf",&h.x,&h.y); scanf("%lf%lf",&q.x,&q.y); scanf("%lf%lf",&hs.x,&hs.y); scanf("%lf%lf",&wt.x,&wt.y); scanf("%lf%lf",&ms.x,&ms.y); scanf("%lf%lf",&mt.x,&mt.y); if(!jiao(h,q,hs,wt) && !jiao(h,q,ms,mt)){cout<<"YES";return 0;} else { bool flag1=0,flag2=0; double A=mt.y-ms.y,B=ms.x-mt.x,C=ms.y*mt.x-ms.x*mt.y; k=-2*(A*q.x+B*q.y+C)/(A*A+B*B); poi pie,pie2; pie.x=q.x+k*A,pie.y=q.y+k*B; if(jiao(pie,h,ms,mt) && !jiao(pie,h,hs,wt))flag1=1; k=-2*(A*h.x+B*h.y+C)/(A*A+B*B); pie2.x=h.x+k*A,pie2.y=h.y+k*B; if(jiao(pie2,q,ms,mt) && !jiao(pie2,q,hs,wt))flag2=1; if(flag1 && flag2){cout<<"YES";return 0;} } cout<<"NO"; return 0; }
100分
有道dp 当时忘了更结果发现题忘了Orz 大概是bzoj吧
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> using namespace std; //DP一般看规律 int n; const int maxn=26 + 5; char str[1100000]; int sum[maxn],ma[maxn][maxn],mi[maxn][maxn],sma[maxn][maxn],smi[maxn][maxn]; int dp[maxn][maxn]; int ans=-1; inline void qj(int a,int j) { if(sma[a][j]!=sum[j])ans=max(ans,dp[a][j]-ma[a][j]); else if(smi[a][j]!=sum[j])ans=max(ans,dp[a][j]-mi[a][j]); if(dp[a][j]<ma[a][j]) { mi[a][j]=ma[a][j]; smi[a][j]=sma[a][j]; ma[a][j]=dp[a][j]; sma[a][j]=sum[j]; } if(dp[a][j]>ma[a][j] && dp[a][j]<mi[a][j]) { mi[a][j]=dp[a][j]; smi[a][j]=sum[j]; } } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&n);scanf("%s",str+1); for(int i=1;i<=n;i++) { int a=str[i]-'a'; sum[a]++; for(int j=0;j<26;j++) if(a!=j) { dp[a][j]++; qj(a,j); dp[j][a]--; qj(j,a); } } printf("%d",ans); return 0; }
100分
当天200分好像还前几名 Orz