【思维】uva11261Bishops

来源:互联网 发布:淘宝怎么搜苍蝇水 编辑:程序博客网 时间:2024/06/04 19:45

题目链接
题目描述:在nn1<=n<=40000的棋盘上有m0<=m<=10000个象,象攻击它所在的主、从对角线,求有多少格子没有被攻击。

这道题难就难在数据大,易超时。
这道题的朴素算法O(nn)或者O(nm)都会超时。

先说O(nn)的朴素算法:
利用补集的思想:计算被象攻击的格子的个数。遍历主对角线,再遍历从对角线,减去被重复计算的格子。

下面的这种奇葩方法可以在遍历从对角线时,O(1)计算出它与几条已经被攻击过的主对角线相交(即重复计算的格子有多少)。
通过画图分析得:每一条从对角线都与一段奇偶性相同的主对角线相交。于是可以将主对角线分类(以编号的奇偶性分类),计算前缀和(该主对角线被攻击就为1,否则为0)。
这里写图片描述

在写代码时注意细节。
我是把两种主对角线放在一起算的,用下标的奇偶性来区分。具体操作见代码。

附代码

#include <iostream>#include <cstdio>#include <cstring>#define MAXN 80005using namespace std;int n ,m ,ans ,a ,b ;int sum[MAXN] ;bool flag[MAXN] ,flag2[MAXN] ;int main(){    int T ;    scanf("%d",&T);    for(int cas=1;cas<=T;++cas)    {        ans=0 ;        memset(sum,0,sizeof sum);        memset(flag,0,sizeof flag);        memset(flag2,0,sizeof flag2);        scanf("%d%d",&n,&m);        for(int i=0;i<m;++i)        {            scanf("%d%d",&a,&b);            flag[a-b+n]=flag2[a+b-1]=1 ;        }        if(flag[1])ans=1,sum[1]=1 ;        for(int i=2;i<n+n;++i)        {            if(flag[i])            {                if(i<=n)ans+=i ;                else ans+=n+n-i ;            }            sum[i]=sum[i-2]+flag[i] ;        }        for(int i=1;i<=n;++i)            if(flag2[i])            {                ans+=i ;                ans-=sum[i-1+n]-sum[1-i+n]+flag[1-i+n] ;            }        for(int i=1;i<n;++i)            if(flag2[n+n-i])            {                ans+=i;                ans-=sum[i-1+n]-sum[1-i+n]+flag[1-i+n] ;            }        printf("Case #%d: %d\n",cas,n*n-ans);    }    return 0;}
1 0
原创粉丝点击