• NOI 2008 Day2 ~ 2009


    [NOI2008]糖果雨

    啊啊啊先挖坑,推荐

    http://blog.sina.com.cn/s/blog_86942b1401015yln.html

    CODE:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=2003;
    const int maxm=4003;
    const int maxc=1e6+10;
    int q,len,n,m;
    int s[2][maxn][maxm],x[maxc],y[maxc];
    
    inline int lowbit(int x){return x&-x;}
    inline void add(int p,int x,int y,int v)
    {
        x++,y++;
        for(;x<maxn;x+=lowbit(x))
            for(int i=y;i<maxm;i+=lowbit(i)) s[p][x][i]+=v;
    }
    
    inline int sum(int p,int x,int y)
    {
        if(x<0 || y<0) return 0;
        int k=0;
        if(++x>n) x=n+1; if(++y>m) y=m+1;
        for(;x;x-=lowbit(x))
            for(int i=y;i;i-=lowbit(i)) k+=s[p][x][i];
        return k;
    }
    
    inline void update(int t,int c,int l,int r,int d)
    {
        x[c]=(t-l*d+n)%n,y[c]=r-l;
        add(0,x[c],y[c]+x[c],1),add(1,x[c],y[c]-x[c]+n,1);
    }
    
    inline void del(int c)
    {
        add(0,x[c],y[c]+x[c],-1),add(1,x[c],y[c]-x[c]+n,-1);
    }
    
    inline int area(int p,int x,int y,int xx,int yy)
    {
        return sum(p,xx,yy)+sum(p,x-1,y-1)-sum(p,x-1,yy)-sum(p,xx,y-1);
    }
    
    inline int ask(int t,int l,int r)
    {
        int d=r==len;
        return area(0,t,t+l,t+r,m)+area(0,0,l+t-n,t+r-n-d,m)+area(1,n-r+t+d,l-t,n,m)+area(1,t-r,l-t+n,t-1,m);
    }
    
    int main()
    {
        scanf("%d%d",&q,&len);
        n=len<<1,m=len<<2;
        while(q--)
        {
            int t,c,l,r,d,p;
            scanf("%d%d",&p,&t);
            if(p==1)
            {
                scanf("%d%d%d%d",&c,&l,&r,&d);
                update(t,c,l,r,d);
            }
            else if(p==2)
            {
                scanf("%d%d",&l,&r);
                printf("%d
    ",ask(t%n,l,r));
            }
            else
            {
                scanf("%d",&c);
                del(c);
            }
        }
        return 0;
    }
    View Code

    [NOI2009]诗人小G

    注意字母和空格也算‘字符’。

    f[i]表示考虑到i这一句诗的最少花费。

    我们显然有经典的1D1D模型:f[i]=min(f[j]+cost[j+1][i]);

    然而n^2只有30(或者20)

    想办法啊,观察cost,'发现'满足四边形不等式(可以直接打表观察决策单调的规律),那么f[i]就具有决策单调性,每个f[j]可以更新的f[i]是一个区间,而且所有的f[j]的区间不重不漏,发现我们总能找到一个i,使得i之前的f[i]不需要f[j]达到最优,而之后的总可以借助f[j]达到最优,那么用一个队列存所有的线段以及用谁更新,每次先弹掉右端小于当前i的区间(其实每次只弹一个),然后用队首更新f[i],入队的时候尝试通过二分把队尾的区间右端往回压(当队尾的左端点都是i更新更优的时候,直接弹掉q[top]),即找到i和q[top]的更新分界点,入队就好了。nlogn的吧。

    CODE:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=1e5+10;
    struct point
    {
        int l,r,p;
    }q[maxn*20];
    int n,T;
    long double L,P,sum[maxn],f[maxn];
    int ans[maxn],nans,from[maxn];
    char ss[maxn][55];
    
    inline long double Pow(long double x,long long b)
    {
        if(x<0)x=-x;
        long double res=1;
        for(;b;b>>=1)
        {
            if(b&1) res=res*x;
            x=x*x;
        }
        return res;
    }
    
    inline long double cal(int j,int i)
    {
        return f[j]+Pow(sum[i]-sum[j]+i-j-1-L,P);
    }
    
    int find(point t,int x)
    {
        int l=t.l-1,r=t.r+1;
        while(l+1<r)
        {
            int mid=(l+r)>>1;
            if(cal(t.p,mid)<cal(x,mid))
                l=mid;
            else r=mid;
        }
        return r;
    }
    
    inline void dp()
    {
        int head=1,tail=0;
        q[++tail]=(point){0,n,0};
        for(int i=1;i<=n;i++)
        {
            if(head<=tail && q[head].r<i) head++;
            f[i]=cal(q[head].p,i);
            from[i]=q[head].p;
            if(head>tail || cal(i,n)<=cal(q[tail].p,n))
            {
                while(head<=tail && cal(i,q[tail].l)<=cal(q[tail].p,q[tail].l)) tail--;
                if(head>tail) q[++tail]=(point){i,n,i};
                else
                {
                    int pos=find(q[tail],i);
                    q[tail].r=pos-1;
                    q[++tail]=(point){pos,n,i};
                }
            }
        }
    }
    
    inline void print()
    {
        int tmp=n;
        nans=0;
        while(1)
        {
            ans[++nans]=tmp;
            if(tmp==0) break;
            tmp=from[tmp];
        }
        for(int i=nans;i>1;i--)
        {
            int be=ans[i]+1;
            for(int j=be;j<=ans[i-1];j++)
                printf("%s%c",ss[j]+1,j==ans[i-1]?'
    ':' ');
        }
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            memset(f,0,sizeof(f));
            scanf("%d%Lf%Lf",&n,&L,&P);
            for(int i=1;i<=n;i++)
            {
                scanf("%s",ss[i]+1);
                sum[i]=sum[i-1]+strlen(ss[i]+1);
            }
            dp();
            if(f[n]>1000000000000000000LL)
            {
                printf("Too hard to arrange
    ");
                printf("--------------------");
                if(T) printf("
    ");
                continue;
            }
            printf("%.0Lf
    ",f[n]);
            print();
            printf("--------------------");
            if(T) printf("
    ");
        }
        return 0;
    }
    View Code

    [NOI2009]植物大战僵尸

    啊。。很棘手的一道题。

    一眼最大权闭合子图,可是有毛病的啊,图中会有环。

    想想就会发现,对于环来说,我们肯定无论如何也得不到环中的分,所以环中的点所保护的点当然也无法得分,所以要通过拓扑来忽略这些点,删掉环和从环伸出去的点?反向拓扑。

    然后就很傻了,模板。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int maxn=610*610*6+10;
    const int inf=1e9;
    struct point
    {
        int to;
        int nxt;
        int c;
    }edge1[maxn],edge[maxn];
    int n,m,cnt=0,s,t,sum,tot1,tot;
    int level[maxn],vis[maxn],val[maxn];
    int head1[maxn],head[maxn],in[maxn];
    int map[50][50];
    
    inline void add1(int u,int v)
    {
        tot1++;
        edge1[tot1].to=v;
        edge1[tot1].nxt=head1[u];
        head1[u]=tot1;
    }
    
    inline void add(int u,int v,int c)
    {
        edge[tot].to=v;
        edge[tot].nxt=head[u];
        edge[tot].c=c;
        head[u]=tot;
        tot++;
        
        edge[tot].to=u;
        edge[tot].nxt=head[v];
        edge[tot].c=0;
        head[v]=tot;
        tot++;    
    }
    
    inline void Topo()
    {
        queue<int> q;
        for(int i=1;i<=n*m;++i)
            if(in[i]==0)
            {
                q.push(i);
                vis[i]=1;    
            }
        while(!q.empty())
        {
            int tt=q.front();
            q.pop();
            for(int i=head1[tt];i;i=edge1[i].nxt)
            {
                int v=edge1[i].to;
                in[v]--;
                if(in[v]==0)
                    q.push(v);    
            }    
        }
    }
    
    inline bool Bfs()
    {
        queue<int> q;
        memset(level,-1,sizeof(level));
        level[s]=1;
        q.push(s);
        while(!q.empty())
        {
            int tt=q.front();
            q.pop();
            for(int i=head[tt];~i;i=edge[i].nxt)
            {
                int v=edge[i].to;
                if(level[v]==-1 && edge[i].c)
                {
                    level[v]=level[tt]+1;
                    q.push(v);    
                }
            }
        }    
        if(level[t]==-1) return false;
        return true;
    }
    
    int dfs(int x,int low)
    {
        if(x==t || low==0)
            return low;
        int res=0;
        for(int i=head[x];~i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(level[v]==level[x]+1 && edge[i].c)
            {
                int ww=dfs(v,min(low,edge[i].c));
                low-=ww;
                res+=ww;
                edge[i].c-=ww;
                edge[i^1].c+=ww;
                if(low==0) break;
            }
        }    
        if(res!=low || res==0)
            level[x]=-1;
        return res;
    }
    
    int Dinic()
    {
        int res=0;
        while(Bfs())
        {
            res+=dfs(s,inf);
        }
        return res;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        s=0,t=m*n+1;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                map[i][j]=++cnt;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
            {
                int vv,nn;
                scanf("%d%d",&vv,&nn);
                val[map[i][j]]=vv;
                for(int t=1;t<=nn;t++)
                {
                    int xx,yy;
                    scanf("%d%d",&xx,&yy);
                    xx++,yy++;
                    add1(map[i][j],map[xx][yy]);
                    in[map[xx][yy]]++;
                }
                if(j!=m)
                {
                    add1(map[i][j+1],map[i][j]);
                    in[map[i][j]]++;    
                }
            }
        Topo();
        memset(head,-1,sizeof(head));
        for(int x=1;x<=m*n;++x)
        if(!in[x])
        {
            if(val[x]>0)
            {
                add(s,x,val[x]);
                sum+=val[x];    
            }
            if(val[x]<0)
                add(x,t,-val[x]);
            for(int i=head1[x];i;i=edge1[i].nxt)
            {
                int v=edge1[i].to;
                if(!in[x])
                    add(v,x,inf);    
            }    
        }
        int Mincut=Dinic();
        printf("%d",sum-Mincut);
        return 0;
    }
    View Code

    [NOI2009]管道取珠

    很可爱的一道题/

    只要发现根据乘法原理,所谓Ai^2就是再搬一套双筒管放在下面,使得上下系统同时达到同种状态的操作方案数,那就很naive了。

    用f[i][s1][s2]表示操作i步,上面的双筒的上管已经弹出s1个球,下面的双筒的上管已经弹出s2个球的方案数。第一维可以压掉。

    O((n+m)n^2)的,卡着过。

    CODE:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=505;
    const int mod=1024523;
    int n,m;
    long long f[2][maxn][maxn];
    char a[maxn],b[maxn],c[maxn];
    
    int main()
    {
        scanf("%d%d",&n,&m);
        scanf("%s",a+1);
        scanf("%s",b+1);
    
            
        f[0][0][0]=1;
        int cur=1;
        for(int t=1;t<=n+m;t++)
        {
            memset(f[cur],0,sizeof(f[cur]));
            for(int i=max(0,t-m);i<=min(n,t);i++)
                for(int j=max(0,t-m);j<=min(n,t);j++)
                {
                    if(t-i && t-j && b[t-i]==b[t-j])
                        f[cur][i][j]=(f[cur][i][j]+f[cur^1][i][j])%mod;
                    if(i && j && a[i]==a[j])
                        f[cur][i][j]=(f[cur][i][j]+f[cur^1][i-1][j-1])%mod;
                    if(t-j && i && a[i]==b[t-j])
                        f[cur][i][j]=(f[cur][i][j]+f[cur^1][i-1][j])%mod;
                    if(t-i && j && b[t-i]==a[j])
                        f[cur][i][j]=(f[cur][i][j]+f[cur^1][i][j-1])%mod;
                }    
            cur^=1;
        }
        printf("%d",f[cur^1][n][n]);
        return 0;
    }
    View Code
  • 相关阅读:
    JDBC05JDBC控制事务4
    JDBC05详解各个类2
    JDBC05JDBC工具类3
    Tomcat&Servlet7_Tomcat2
    MySQL多表&事务04事务2
    JDBC连接池&JDBCTemplate06_Spring JDBC2
    JDBC连接池&JDBCTemplate06_数据库连接池1
    Tomcat&Servlet7_web服务器软件概述1
    MySQL多表&事务04DCL3
    用 JavaScript 的匿名函数理解 C# 的委托
  • 原文地址:https://www.cnblogs.com/linda-fcj/p/9098918.html
Copyright © 2020-2023  润新知