UVA 12633 Super Rooks on Chessboard (生成函数+FFT)

题面传送门

题目大意:给你一张网格,上面有很多骑士,每个骑士能横着竖着斜着攻击一条直线上的格子,求没被攻击的格子的数量总和

好神奇的卷积

假设骑士不能斜着攻击

那么答案就是没被攻击的 行数*列数

接下来考虑斜着攻击对答案的贡献

以左下角为坐标原点建立坐标系,发现一条对角线的点的$(x+y)$坐标是相同的

考虑卷积,设计两个生成函数$a,b$

如果第i行没骑士,则$a_{i}=1$,反之为$0$

如果第i列没骑士,则$b_{i}=1$,反之为$0$

我们对两个式子进行卷积,可以求出每一条对角线上还有多少个空格子

答案就是$\sum$ 没有骑士的对角线的空格子数

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define N1 (1<<18)
 6 #define M1 (N1<<1)
 7 #define ll long long
 8 #define dd double
 9 #define idx(X) (X-‘a‘)
10 using namespace std;
11
12 int gint()
13 {
14     int ret=0,fh=1; char c=getchar();
15     while(c<‘0‘||c>‘9‘){if(c==‘-‘)fh=-1;c=getchar();}
16     while(c>=‘0‘&&c<=‘9‘){ret=ret*10+c-‘0‘;c=getchar();}
17     return ret*fh;
18 }
19 int T,n,m,num,r[N1];
20 int nt[N1],x[N1],y[N1];
21 const dd pi=acos(-1);
22
23 struct cp{
24 dd x,y;
25 friend cp operator + (const cp &s1,const cp &s2){ return (cp){s1.x+s2.x,s1.y+s2.y}; }
26 friend cp operator - (const cp &s1,const cp &s2){ return (cp){s1.x-s2.x,s1.y-s2.y}; }
27 friend cp operator * (const cp &s1,const cp &s2){ return (cp){s1.x*s2.x-s1.y*s2.y,s1.y*s2.x+s1.x*s2.y}; }
28 }a[N1],b[N1],c[N1];
29
30 void init()
31 {
32     memset(a,0,sizeof(a));
33     memset(b,0,sizeof(b));
34     memset(c,0,sizeof(c));
35     memset(nt,0,sizeof(nt));
36 }
37 void FFT(cp *s,int len,int type)
38 {
39     int i,j,k; cp wn,w,t;
40     for(i=0;i<len;i++) if(i<r[i]) swap(s[i],s[r[i]]);
41     for(k=2;k<=len;k<<=1)
42     {
43         wn=(cp){cos(2.0*type*pi/k),sin(2.0*type*pi/k)};
44         for(i=0;i<len;i+=k)
45         {
46             w=(cp){1,0};
47             for(j=0;j<(k>>1);j++,w=w*wn)
48             {
49                 t=w*s[i+j+(k>>1)];
50                 s[i+j+(k>>1)]=s[i+j]-t;
51                 s[i+j]=s[i+j]+t;
52             }
53         }
54     }
55 }
56 void FFT_Main(int len)
57 {
58     FFT(a,len,1); FFT(b,len,1);
59     for(int i=0;i<len;i++) c[i]=a[i]*b[i];
60     FFT(c,len,-1);
61     for(int i=0;i<len;i++) c[i].x=c[i].x/len;
62 }
63
64 int main()
65 {
66     scanf("%d",&T); int t;
67     for(t=1;t<=T;t++){
68
69     init();
70     scanf("%d%d%d",&n,&m,&num);
71     int i,j,de,len,L; ll ans=0;
72     for(i=1;i<=num;i++) x[i]=n-gint(), y[i]=gint()-1, a[x[i]].x=-1, b[y[i]].x=-1, nt[x[i]+y[i]]=1;
73     for(i=0;i<n;i++) a[i].x++;
74     for(i=0;i<m;i++) b[i].x++;
75     for(len=1,L=0;len<n+m-1;len<<=1,L++);
76     for(i=0;i<len;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
77     FFT_Main(len);
78     for(i=0;i<=n+m-2;i++) if(!nt[i]) ans+=(int)(c[i].x+0.1);
79     printf("Case %d: %lld\n",t,ans);
80
81     }
82     return 0;
83 }

原文地址:https://www.cnblogs.com/guapisolo/p/10353513.html

时间: 2024-10-03 14:38:40

UVA 12633 Super Rooks on Chessboard (生成函数+FFT)的相关文章

[UVA 12633] Super Rooks on Chessboard FFT+计数

如果只有行和列的覆盖,那么可以直接做,但现在有左上到右下的覆盖. 考虑对行和列的覆盖情况做一个卷积,然后就有了x+y的非覆盖格子数. 然后用骑士的左上到右下的覆盖特判掉那些x+y的格子就可以了. 注意题意,Row是从上到下来的,被坑得好惨. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<ctim

UVA - 12633 Super Rooks on Chessboard FFT

题目链接:点这里 题意: 给你一个矩阵R*C,n个点,与给的的n个点同一列同一行,同一条主对角线上的点都被染黑 问你最后有多少个点没有被染黑 题解: 把每一列每一行没有被染黑的x,y找出来,其任意组合起来是没这种情况下的答案(同一条主对角线上的点都被染黑) 对于 x - y,我们可以拿来判断两个点是不是相同的一条主对角线上 那么对x.-y进行任意组合,FFT加速 总的答案就是,没有被染过行数*没有被染过的列数 - (找不到相同的x- y) 具体看代码吧 #include<bits/stdc++.

UVA - 11134 Fabled Rooks[贪心 问题分解]

UVA - 11134 Fabled Rooks We would like to place n rooks, 1 ≤ n ≤ 5000, on a n × n board subject to the following restrictions The i-th rook can only be placed within the rectan- gle given by its left-upper corner (xli,yli) and its right- lower corner

UVa 10161 Ant on a Chessboard

一道数学水题,找找规律. 首先要判断给的数在第几层,比如说在第n层.然后判断(n * n - n + 1)(其坐标也就是(n,n)) 之间的关系. 还要注意n的奇偶.  Problem A.Ant on a Chessboard  Background One day, an ant called Alice came to an M*M chessboard. She wanted to go around all the grids. So she began to walk along t

uva 11134 - Fabled Rooks(主要在贪心方法及其实现)

#用到了贪心方法. #这个贪心刚开始想错了方法,后来想到了新的方法,AC 刚开始错在了按左端点升序排序并从左往右取最左端能取的格子,这个方法显然不能符合要求 比如下面这组数据: 2 1 1 3 3 1 1 3 3 2 2 2 2 错误代码: #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; struct note {

UVA 12298 Super Poker II (FFT)

#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int N = 1000005; const long double pi = acos(-1.0); struct Complex { long double r,i; Complex(long double r=0, long double i=0):r(r),

UVa12298 Super Poker II(母函数 + FFT)

题目 Source http://acm.hust.edu.cn/vjudge/problem/23590 Description I have a set of super poker cards, consisting of an infinite number of cards. For each positive composite integer p, there are exactly four cards whose value is p: Spade(S), Heart(H),

【BZOJ3771】Triple 生成函数+FFT

[BZOJ3771]Triple Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: “这把斧头,是不是你的?” 樵夫一看:“是啊是啊!” 水神把斧头扔在一边,又拿起一个东西问: “这把斧头,是不是你的?” 樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!” 水神又把手上的东西扔在一边,拿起第三个东西问: “这把斧头,是不是你的?” 樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了. 于是他又一次答:“

HDU 5307 He is Flying (生成函数+FFT)

题目传送门 给你一个长度为$n$的自然数序列$a$,定义一段区间的权值为这一段区间里所有数的和,分别输出权值为$[0,\sum a_{i}]$的区间的长度之和 想到了生成函数的话,这道题并不难做.但很多细节真是不太好搞 我们首先预处理出前缀和s,那么一段区间$[l,r]$的权值就是$s_{r}-s_{l-1}$ 容易联想到卷积 第一个多项式是 区间右端点的前缀和 作为指数的生成函数,每一项的系数是 右端点的编号之和 第二个多项式是 区间左端点的前缀和 作为指数的生成函数,每一项的系数是 左端点的