zoukankan      html  css  js  c++  java
  • UVa12633 Super Rooks on Chessboard(容斥 + FFT)

    题目

    Source

    http://acm.hust.edu.cn/vjudge/problem/42145

    Description

    Let’s assume there is a new chess piece named Super-rook. When placed at a cell of a chessboard, it attacks all the cells that belong to the same row or same column. Additionally it attacks all the
    cells of the diagonal that goes from top-left to bottom-right direction through that cell.
    N Super-rooks are placed on a R × C chessboard. The rows are numbered 1 to R from top to bottom and columns are numbered 1 to C from left to right of the chessboard. You have to find the number of cells of the chessboard which are not attacked by any of the Super-rooks.
    The picture on the left shows the attacked cells when a Super-rook is placed at cell (5, 3) of a 6 × 6 chessboard. And the picture on the right shows the attacked cells when three Super-rooks are placed at cells (3, 4), (5, 3) and (5, 6). These pictures (Left and right one) corresponds to the first and second sample input respectively.

    Input

    First line of input contains an integer T (1 ≤ T ≤ 20) which is the number of test cases. The first line of each test case contains three integers R, C and N (1 ≤ R, C, N ≤ 50, 000). The next N lines contain two integers r, c giving the row and column of a Super-rook on the chessboard (1 ≤ r ≤ R and 1 ≤ c ≤ C). You may assume that two Super-rooks won’t be placed on the same cell.

    Output

    For each test case, output the case number followed by the number of cells which are not attacked by any of the Super-rook.

    Sample Input

    2
    6 6 1
    5 3
    6 6 3
    3 4
    5 3
    5 6

    Sample Output

    Case 1: 22
    Case 2: 9

    分析

    题目大概说一个R*C的棋盘上有N个超级车棋子,这种棋子可以往水平、竖直和主对角线方向移动任意格,问棋盘没有被这些超级车攻击的格子有多少个。

    这题解法从叉姐的一个讲义中看到的,自己想了下,实现了下就AC了。

    解法就是利用容斥去求得有多少个格子被攻击:

    • 被攻击的行格子数 + 被攻击的列格子数 + 被攻击的主对角线格子数 - 行列交叉格子数 - 行对角交叉格子数 + 行列主对角交叉格子数

    一开始不妨给行、列、对角编好号。行列从0开始上到下、左到右这样;而对于主对角线,可以知道主对角线上每一格的的行坐标-列坐标都是定值,所以可以从右上到左下从0到R+C-1给每条对角线编号,而对于任意一格(x,y)其所属对角线编号就等于x-y+C-1。

    然后上面那个式子前面5个求没什么问题,就是比较复杂。。关键是最后一个,相当于求。。直接截图吧不会表达。。

    代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define MAXN 133333
    const double PI=acos(-1.0);
    
    struct Complex{
    	double real,imag;
    	Complex(long double _real,long double _imag):real(_real),imag(_imag){}
    	Complex(){}
    	Complex operator+(const Complex &cp) const{
    		return Complex(real+cp.real,imag+cp.imag);
    	}
    	Complex operator-(const Complex &cp) const{
    		return Complex(real-cp.real,imag-cp.imag);
    	}
    	Complex operator*(const Complex &cp) const{
    		return Complex(real*cp.real-imag*cp.imag,real*cp.imag+cp.real*imag);
    	}
    	void setValue(long double _real=0,long double _imag=0){
    		real=_real; imag=_imag;
    	}
    };
    
    int len;
    Complex wn[MAXN],wn_anti[MAXN];
    
    void FFT(Complex y[],int op){
    	for(int i=1,j=len>>1,k; i<len-1; ++i){
    		if(i<j) swap(y[i],y[j]);
    		k=len>>1;
    		while(j>=k){
    			j-=k;
    			k>>=1;
    		}
    		if(j<k) j+=k;
    	}
    	for(int h=2; h<=len; h<<=1){
    		Complex Wn=(op==1?wn[h]:wn_anti[h]);
    		for(int i=0; i<len; i+=h){
    			Complex W(1,0);
    			for(int j=i; j<i+(h>>1); ++j){
    				Complex u=y[j],t=W*y[j+(h>>1)];
    				y[j]=u+t;
    				y[j+(h>>1)]=u-t;
    				W=W*Wn;
    			}
    		}
    	}
    	if(op==-1){
    		for(int i=0; i<len; ++i) y[i].real/=len;
    	}
    }
    void Convolution(Complex A[],Complex B[],int n){
    	for(len=1; len<(n<<1); len<<=1);
    	for(int i=n; i<len; ++i){
    		A[i].setValue();
    		B[i].setValue();
    	}
    	
    	FFT(A,1); FFT(B,1);
    	for(int i=0; i<len; ++i){
    		A[i]=A[i]*B[i];
    	}
    	FFT(A,-1);
    }
    
    int x[55555],y[55555];
    Complex A[MAXN],B[MAXN];
    long long R[55555],C[55555],D[55555*2];
    
    long long get_sum(long long *x,int l,int r){
    	if(l==0) return x[r];
    	return x[r]-x[l-1];
    }
    
    int main(){
    	for(int i=0; i<MAXN; ++i){
    		wn[i].setValue(cos(2.0*PI/i),sin(2.0*PI/i));
    		wn_anti[i].setValue(wn[i].real,-wn[i].imag);
    	}
    	int t,r,c,n;
    	scanf("%d",&t);
    	for(int cse=1; cse<=t; ++cse){
    		scanf("%d%d%d",&r,&c,&n);
    		memset(R,0,sizeof(R));
    		memset(C,0,sizeof(C));
    		memset(D,0,sizeof(D));
    		for(int i=0; i<n; ++i){
    			scanf("%d%d",x+i,y+i);
    			--x[i]; --y[i];
    			R[x[i]]=1; C[y[i]]=1; D[x[i]-y[i]+c-1]=1;
    		}
    		long long ans=0;
    		for(int i=0; i<r; ++i){
    			if(R[i]) ans+=c;
    		}
    		for(int i=0; i<c; ++i){
    			if(C[i]) ans+=r;
    		}
    		
    		for(int i=0; i<r+c-1; ++i){
    			if(D[i]==0) continue;
    			if(i<c) ans+=min(r,i+1);
    			else ans+=min(r-i+c-1,c);
    		}
    		for(int i=1; i<r; ++i) R[i]+=R[i-1];
    		for(int i=1; i<c; ++i) C[i]+=C[i-1];
    		ans-=R[r-1]*C[c-1];
    		for(int i=0; i<r+c-1; ++i){
    			if(D[i]==0) continue;
    			if(i<c){
    				int x=0,y=c-i-1;
    				int k=min(r-x,c-y);
    				ans-=get_sum(R,x,x+k-1);
    				ans-=get_sum(C,y,y+k-1);
    			}else{
    				int x=i-c+1,y=0;
    				int k=min(r-x,c-y);
    				ans-=get_sum(R,x,x+k-1);
    				ans-=get_sum(C,y,y+k-1);
    			}
    		}
    		
    		for(int i=0; i<r; ++i){
    			A[i].setValue(get_sum(R,i,i));
    		}
    		for(int i=0; i<c; ++i){
    			B[c-i-1].setValue(get_sum(C,i,i));
    		}
    		for(int i=r; i<c; ++i){
    			A[i].setValue();
    		}
    		for(int i=c; i<r; ++i){
    			B[i].setValue();
    		}
    		Convolution(A,B,max(r,c));
    		for(int i=0; i<r+c-1; ++i){
    			if(D[i]==0) continue;
    			ans+=(long long)(A[i].real+0.5);
    		}
    		
    		printf("Case %d: %lld
    ",cse,(long long)r*c-ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    怎么解决Chrome浏览器崩溃“STATUS_INVALID_IMAGE_HASH”的问题
    Windows下PHP如何选择Thread Safe和Non ThreadSafe版本
    Windows环境下安装Yaf框架
    创建Redis-Cluster集群常见问题-解决方案
    Linxu下PHP版本升级
    Linxu下Yii2的POST提交被拒经历
    彻底搞懂 Redis 事务
    python模块之psutil详解
    iptables学习笔记
    incaseformat 病毒事件企业解决流程
  • 原文地址:https://www.cnblogs.com/WABoss/p/5843664.html
Copyright © 2011-2022 走看看