zoukankan      html  css  js  c++  java
  • bzoj4558[JLoi2016]方 容斥+count

    4558: [JLoi2016]方

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 452  Solved: 205
    [Submit][Status][Discuss]

    Description

    上帝说,不要圆,要方,于是便有了这道题。由于我们应该方,而且最好能够尽量方,所以上帝派我们来找正方形

    上帝把我们派到了一个有N行M列的方格图上,图上一共有(N+1)×(M+1)个格点,我们需要做的就是找出这些格点形

    成了多少个正方形(换句话说,正方形的四个顶点都是格点)。但是这个问题对于我们来说太难了,因为点数太多

    了,所以上帝删掉了这(N+1)×(M+1)中的K个点。既然点变少了,问题也就变简单了,那么这个时候这些格点组成

    了多少个正方形呢?

    Input

    第一行三个整数 N, M, K, 代表棋盘的行数、 列数和不能选取的顶点个数。 保证 N, M >= 1, K <=(N + 1) ×

    (M + 1)。约定每行的格点从上到下依次用整数 0 到 N 编号,每列的格点依次用 0到 M 编号。接下来 K 行,每

    行两个整数 x,y 代表第 x 行第 y 列的格点被删掉了。保证 0 <=x <=N<=10^6, 0 <=y<=M<=10^6,K<=2*1000且不

    会出现重复的格点。

    Output

    仅一行一个正整数, 代表正方形个数对 100000007( 10^8 + 7) 取模之后的值

    Sample Input

    2 2 4
    1 0
    1 2
    0 1
    2 1

    Sample Output

    1

     

    并没有调出来,调出来也是TLE

    容斥,ans=所有格点正方形-至少含一个非法点正方形+至少含2个-至少含3个+至少含4个
    容斥很简单,主要就是统计方案难啊

    由于正方形有斜放的,我们规定一个n*n的框架
    顶点在框架边上的正方形有i个
    考虑对于每一个非法点,除去以它为顶点的正方形(正方/斜放都要考虑)
    枚举两个非法点,计算以它们为顶点的正方形另外两个点,对于含2,3,4的贡献答案。
     
    判断正方形的顶点是否存在,应该用hash表,由于懒,我用了stl,估计要挂。。
     
    推荐blog
    http://blog.csdn.net/huanghongxun/article/details/51267460

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<map>
    #define mod 100000007
    #define ll long long
    #define N 2005
    using namespace std;
    int n,m,num,px[N],py[N];
    ll ans,t1,t2,t3,t4;
    typedef pair<int,int>pii;
    map<pii,bool>mp;
    void calc(int x,int y,int z){//计算顶点在正方形框架边,顶点上的正方形个数 
        z=min(z,x+y);
        if(!z)return;
        t1=(t1+1ll*(z+3)*z/2)%mod;
        if(z>x)t1=(t1-1ll*(z-x)*(z-x+1)/2)%mod;
        if(z>y)t1=(t1-1ll*(z-y)*(z-y+1)/2)%mod;
    }
    bool check(int x,int y){return x>=0&&x<=n&&y>=0&&y<=m;}
    void update(int x1,int y1,int x2,int y2){
        if(!check(x1,y1)||!check(x2,y2))return;
        int res=0;
        if(mp[make_pair(x1,y1)])res++;
        if(mp[make_pair(x2,y2)])res++;
        t2++;t3+=res;if(res==2)t4++;
    }
    
    void solve(int x1,int y1,int x2,int y2){
        int dx=x2-x1,dy=y2-y1;
        update(x1+dy,y1-dx,x2+dy,y2-dx);  
        update(x1-dy,y1+dx,x2-dy,y2+dx);  
        if (abs(dx+dy)&1) return;  
        dy=(dx+dy)>>1; dx-=dy;  
        update(x1+dx,y1+dy,x2-dx,y2-dy);
    }
    int main(){
    #ifdef wsy
        freopen("data.in","r",stdin);
    #else
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
    #endif
        scanf("%d%d%d",&n,&m,&num);
        for(int i=1;i<=num;i++){
            scanf("%d%d",&px[i],&py[i]);
            mp[make_pair(px[i],py[i])]=1;
        }
        for(int i=1;i<=min(n,m);i++)
        ans=(ans+1ll*(m-i+1)*(n-i+1)%mod*i%mod)%mod;
        for(int i=1;i<=num;i++){
            calc(px[i],m-px[i],py[i]);
            calc(px[i],m-px[i],n-py[i]);
            calc(py[i],n-py[i],px[i]);
            calc(py[i],n-py[i],m-px[i]);
            t1=(t1-min(px[i],py[i]))%mod;//减去掉calc重复的方案 
            t1=(t1-min(px[i],n-py[i]))%mod;
            t1=(t1-min(m-px[i],py[i]))%mod;
            t1=(t1-min(m-px[i],n-py[i]))%mod;
            while(t1<0)t1+=mod;
            for(int j=1;j<i;j++)solve(px[i],py[i],px[j],py[j]);
        }
        t2%=mod;t3%=mod;t4%=mod;
        cout<<ans-t1+t2-t3/3+t4/6;
        return 0;
    }//?????
  • 相关阅读:
    unicodedata.normalize()/使用strip()、rstrip()和lstrip()/encode和decode 笔记(具体可看 《Python Cookbook》3rd Edition 2.9~2.11)
    split与re.split/捕获分组和非捕获分组/startswith和endswith和fnmatch/finditer 笔记
    比较字典推导式/dict()/通过键来构造的字典的速率 笔记
    itertools.groupby()/itertools.compress() 笔记
    operator笔记
    slice.indices()/collections.Counter笔记
    deque/defaultdict/orderedict/collections.namedtuple()/collections.ChainMap() 笔记
    实践中总结出来对heapq的一点理解
    学习笔记(42)- 端到端对话到底是什么
    机器翻译-领域专家
  • 原文地址:https://www.cnblogs.com/wsy01/p/8035182.html
Copyright © 2011-2022 走看看