zoukankan      html  css  js  c++  java
  • hdu 5471(状压DP or 容斥)

    想了最复杂的思路,用了最纠结的方法,花了最长的时间,蒙了一种规律然后莫名其妙的过了。 

    MD 我也太淼了。

    后面想了下用状压好像还是挺好写的,而且复杂度也不高。推出的这个容斥的规律也没完全想透我就CAO。

    Count the Grid

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 400    Accepted Submission(s): 86


    Problem Description
    You get a grid of h rows and w columns. Rows are numbered 1, 2, 3, ... , h from top to bottom while columns are numbered 1, 2 , 3, ... , w from left to right. Each cell can be represented by a pair of numbers (x, y), which means this cell is located at row x column y.
    You fill the every cell with an integer ranging from 1 to m.
    Then you start to play with the gird. Every time you chose a rectangle whose upper left cell is (x1, y1) and lower right cell is (x2, y2), finally you calculate the maximum value v of this rectangle.
    After you played n times, you left. When you return, you find that the grid is disappeared. You only remember n rectangles and their corresponding maximum value. You are wondering how many different gird can satisfy your memory. Two grids are different if there is a cell filled different integer.
    Give your answer modulo (109+7).
    Your memory may have some mistakes so that no grid satisfies it, in this case just output 0.
     
    Input
    Multiple test cases. In the first line there is an integer T, indicating the number of test cases. For each test case. First line contain 4 integers h, w, m, n. Next are n lines, each line contain 5 integers x1, y1, x2, y2, v.
    (T=55,1h,w,m104,1x1x2h,1y1y2w,1vm,1n10, there are i test cases for n = i)
     
    Output
    For each test case, please output one line. The output format is "Case #x: ans", x is the case number, starting from 1.
     
    Sample Input
    2 3 3 2 2 1 1 2 2 2 2 2 3 3 1 4 4 4 4 1 1 2 3 3 2 3 4 4 2 2 1 4 3 2 1 2 3 4 4
     
    Sample Output
    Case #1: 28 Case #2: 76475
     
    Source
     
    Recommend
    hujie   |   We have carefully selected several similar problems for you:  5493 5492 5491 5490 5489 
     
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <stdlib.h>
    #include <math.h>
    using namespace std;
    #define MOD 1000000007
    
    int h,w,m,n;
    struct node
    {
        int x1,y1,x2,y2;
        int num;
        int areacnt;
        int area[1010];//记录其中的小区域
    }g[11],tg[11];
    
    struct Rect
    {
        int x1,y1,x2,y2;
    }rect[1010];
    
    bool flag_noans;
    int tmpsaverect[1010];
    int tmprectcnt;
    
    long long savemul[11];
    bool saverectinarea[1010][11];
    bool flagrect[1010];
    bool flagarea[11];
    bool flagg[11];
    int x[22],y[22];
    long long ans;
    long long tmpans;
    long long ansans;
    
    bool cmpgnum(node tl,node tr)
    {
        return tl.num<tr.num;
    }
    
    bool checkareabelong(int rectpoint,int gi)
    {
        if(g[gi].x1<=rect[rectpoint].x1&&g[gi].y1<=rect[rectpoint].y1 && g[gi].x2>=rect[rectpoint].x2&&g[gi].y2>=rect[rectpoint].y2 )
        {
            return 1;
        }
        return 0;
    }
    
    int getrectareanum(int i)
    {
        return (rect[i].y2-rect[i].y1+1)*(rect[i].x2-rect[i].x1+1);
    }
    
    long long quick_pow(int aa,int bb)//a^b
    {
        long long ans_pow=1;
        long long tmp_pow=aa;
        while(bb)
        {
            if(bb&1)
                ans_pow = (ans_pow*tmp_pow)%MOD;
            tmp_pow = (tmp_pow*tmp_pow)%MOD;
            bb>>=1;
        }
        return ans_pow;
    }
    
    long long cnt_bigoneism(int allnum,int bigm)
    {
        return ((quick_pow(bigm,allnum)-quick_pow(bigm-1,allnum))%MOD+MOD)%MOD;
    }
    
    void dfs(int s,int ends,int cnt_nowhave,int tmp_m)
    {
        //明显错了
        if(cnt_nowhave!=0)
        {
            int cnt_inarea=0;
            int cnt_outarea=0;
            for(int i=0;i<tmprectcnt;i++)
            {
                int tmp_flag=0;
                for(int j=0;j<ends;j++)
                {
                    if(flagarea[j]==true)
                    {
                        if( saverectinarea[i][j]==true )
                        {
                            tmp_flag=1;
                            cnt_inarea += getrectareanum( tmpsaverect[i] );
                            break;
                        }
    
                        /*
                        if( tg[j].x1<=rect[tmpsaverect[i]].x1&&tg[j].y1<=rect[tmpsaverect[i]].y1&& tg[j].x2>=rect[tmpsaverect[i]].x2&&tg[j].y2>=rect[tmpsaverect[i]].y2 )
                        {
                            tmp_flag=1;
                            cnt_inarea += getrectareanum( tmpsaverect[i] );
                            break;
                        }
                        */
                    }
                }
                if(tmp_flag==0)
                {
                    cnt_outarea += getrectareanum( tmpsaverect[i] );
                }
    
            }
            if( !(cnt_outarea==0||cnt_inarea==0) )
            {
                long long tmp_sum = ( quick_pow(tmp_m-1,cnt_inarea)*cnt_bigoneism(cnt_outarea,tmp_m) )%MOD;
                ansans = (ansans+savemul[cnt_nowhave]*tmp_sum)%MOD;
            }
        }
        for(int i=s;i<ends;i++)
        {
            flagarea[i]=true;
            dfs(i+1,ends,cnt_nowhave+1,tmp_m);
            flagarea[i]=false;
        }
    }
    
    long long get_numtime(int mxt,int tm)
    {
        //有t个不满足的情况
        memset(flagarea,false,sizeof(flagarea));
        ansans=0;
        dfs(0,mxt,0,tm);
        return ansans;
    }
    
    int main()
    {
        int T;
        int tt=1;
        scanf("%d",&T);
        //设计模式还是很成问题。
        while(T--)
        {
            flag_noans=false;
            scanf("%d%d%d%d",&h,&w,&m,&n);
            for(int i=0;i<n;i++)
            {
                int x1,y1,x2,y2,tmp;
                scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&tmp);
                x[2*i]=x1;
                x[2*i+1]=x2+1;
                y[2*i]=y1;
                y[2*i+1]=y2+1;
    
                g[i].x1=x1;g[i].y1=y1;
                g[i].x2=x2;g[i].y2=y2;
                g[i].num=tmp;
                g[i].areacnt=0;
            }
            x[2*n]=1;
            x[2*n+1]=h+1;
            y[2*n]=1;
            y[2*n+1]=w+1;
            int id=0;//用来标记最小矩形
            sort(x,x+2*(n+1));
            sort(y,y+2*(n+1));
            int prex=1;
            for(int i=0;i<2*(n+1);i++)
            {
                if(x[i]==prex) continue;
                int prey=1;
                for(int j=0;j<2*(n+1);j++)
                {
                    if(y[j]==prey) continue;
                    rect[id].x1=prex;
                    rect[id].y1=prey;
                    rect[id].x2=x[i]-1;
                    rect[id].y2=y[j]-1;
                    prey=y[j];
                    id++;
                }
                prex=x[i];
            }
    
            for(int i=0;i<id;i++)
            {
                for(int j=0;j<n;j++)
                {
                    if( checkareabelong(i,j) == true )
                    {
                        g[j].area[ g[j].areacnt ]=i;
                        g[j].areacnt++;
                    }
                }
            }
    
            //然后就是容斥原理了
    
            int cntother=0;//统计有多少个格子是完全没有拘束的
            for(int i=0;i<id;i++)
            {
                bool signareain=0;
                for(int j=0;j<n;j++)
                {
                    if( checkareabelong(i,j)==true )
                    {
                        signareain=true;
                        break;
                    }
                }
                if(signareain == false)
                {
                    cntother += getrectareanum(i);
                }
            }
            ans=quick_pow(m,cntother);
            sort(g,g+n,cmpgnum);
            memset(flagrect,false,sizeof(flagrect));
            for(int i=0;i<n;i++)
            {
                int ti;
                for(ti=i;ti<n;ti++)
                {
                    if( g[ti].num != g[i].num ) break;
                    tg[ti-i]=g[ti];
                }
                int cntcnt=0;//用来判断不满足条件的情况
                memset(flagg,0,sizeof(flagg));
                ti--;
                //[i,ti] have the same .num
                tmprectcnt=0;
                int tmpcntnum=0;
                for(int j=0;j<id;j++)
                {
                    if( flagrect[j]==true ) continue;//已经计数过的,不需要
                    for(int gi=i;gi<=ti;gi++)
                        if( checkareabelong(j,gi)==true )
                        {
                            flagrect[j]=true;
                            tmpsaverect[tmprectcnt]=j;
                            tmpcntnum += getrectareanum(j);
                            tmprectcnt++;
                            break;
                        }
                    for(int gi=i;gi<=ti;gi++)
                    {
                        if( checkareabelong(j,gi)==true )
                        {
                            if(flagg[gi]==0)
                            {
                                flagg[gi]=1;
                                cntcnt++;
                            }
                        }
                    }
                }
    
                //容斥原理开始
                if(tmprectcnt==0||cntcnt!=ti-i+1)
                {
                    flag_noans=true;
                    break;
                }
    
                for(int j=0;j<tmprectcnt;j++)
                    for(int j1=0;j1<ti-i+1;j1++)
                    {
                        if( tg[j1].x1<=rect[tmpsaverect[j]].x1&&tg[j1].y1<=rect[tmpsaverect[j]].y1&& tg[j1].x2>=rect[tmpsaverect[j]].x2&&tg[j1].y2>=rect[tmpsaverect[j]].y2 )
                        {
                            saverectinarea[j][j1]=true;
                        }
                        else saverectinarea[j][j1]=false;
                    }
    
                tmpans = cnt_bigoneism(tmpcntnum,g[i].num);// 总的个数
                int flag_sign = -1;
                long long num_mul=1;
                for(int j=1;j<=ti-i;j++)
                {
                    savemul[j]=flag_sign*num_mul;
                    //tmpans = tmpans + flag_sign*num_mul*get_numtime(j,ti-i+1,g[i].num);//j个不满足的情况
                    //tmpans = (tmpans%MOD+MOD)%MOD;
                    flag_sign *= -1;
                    //num_mul=(num_mul*(j+1))%MOD;
    
                }
                get_numtime(ti-i+1,g[i].num);
                tmpans = tmpans + ansans;
                ans = (ans*tmpans)%MOD;
                i=ti;//这一步一直忘了
            }
            printf("Case #%d: ",tt++);
            if(flag_noans==true)
                cout<<0<<endl;
            else cout<<(ans%MOD+MOD)%MOD<<endl;
        }
        return 0;
    }
  • 相关阅读:
    初探diskstats
    JVM参数简述
    304 Not Modified 简述
    vmstat命令
    iostat 工具分析I/O性能
    git添加公钥后报错sign_and_send_pubkey: signing failed: agent refused operation
    Mysql ibdata1简述
    Mysql 事务日志(Ib_logfile)
    django项目一:基于django2.2可重用登录与注册模块-前端页面配置
    django项目一:基于django2.2可重用登录与注册模块-url路由和视图
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/4852670.html
Copyright © 2011-2022 走看看