十一模拟赛

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);
}
View Code

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]);
    }
}
View Code

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");
    }
}
正常线段树By鸡神Orz

两个人 一个墙 一面镜子 墙和镜子不相交 问两个人能不能相互看见

计算几何瞎暴力系列

细节:要翻折两遍防止墙挡不住翻折之后但挡得住翻折之前

#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;
}
dp一般看规律

100分

当天200分好像还前几名 Orz

posted @ 2017-10-10 19:21  探险家Mr.H  阅读(135)  评论(0编辑  收藏  举报