Gym 100783C Golf Bot FFT
2024-10-21 04:19:07
大致题意:
给你N个整数和M个整数,问这M个数中,有几个数可以表达成那N个整数中一个或者两个整数的和。
分析:
算是半个裸的FFT。FFT可以用来在nlongn时间内求高精度乘法,我们先模拟一下乘法。
A4A3A2A1A0*B4B3B2B1B0 Ai,Bj表示位数,结果保存在Ck中
4 3 2 1 0(下标)
A4 A3 A2 A1 A0
B4 B3 B2 B1 B0
先不考虑进位
那么C0=A0*B0
C1=A0*B1+A1*B0
Ck=sum(Ai*Bj) (i+j=k)
我们现在看题目是求两个数或者一个数的和是否能在M中匹配到。与上式对比,发现了共同点,i,j的和的下标对应的值即Ck,也就是说我们可以把出现的数字当做位置,出现的位置赋值为1,没有为0,第0位为1,因为可以加0嘛。
样例如下
5 4 3 2 1 0(下标)
1 0 1 0 1 1
X 1 0 1 0 1 1
= 1 0 2 0 3 2 2 2 1 2 1
A 9 8 7 6 5 4 3 2 1 0(下标)
结果不需要再进位,只要k下标对应的值大于0就符合条件。
#include <bits/stdc++.h>
using namespace std; const double PI = acos(-1.0);
struct Complex
{
double x, y;
Complex(double _x = 0.0, double _y = 0.0)
{
x = _x;
y = _y;
}
Complex operator - (const Complex &b)const
{
return Complex(x-b.x, y-b.y);
}
Complex operator + (const Complex &b)const
{
return Complex(x+b.x, y+b.y);
}
Complex operator * (const Complex &b)const
{
return Complex(x*b.x-y*b.y, x*b.y+y*b.x);
}
}; void change(Complex y[], int len)
{
int i, j, k;
for(i = 1, j = len/2; i < len-1; i++)
{
if (i < j) swap(y[i], y[j]);
k = len/2;
while(j >= k)
{
j -= k;
k /= 2;
}
if (j < k) j += k;
}
} void fft(Complex y[], int len, int on)
{
change(y, len);
for(int h = 2; h <= len; h <<= 1)
{
Complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h));
for(int j = 0; j < len; j += h)
{
Complex w(1, 0);
for(int k = j; k < j+h/2; k++)
{
Complex u = y[k];
Complex t = w*y[k+h/2];
y[k] = u+t;
y[k+h/2] = u-t;
w = w*wn;
}
}
}
if (on == -1)
for(int i = 0; i < len; i++)
y[i].x /= len;
} const int maxn=4*200010;
Complex x1[maxn],x2[maxn];
int a[maxn/4];
int sum[maxn]; int main()
{
int N,M;
while(~scanf("%d",&N))
{
memset(a,0,sizeof(a));
int len1=0;
for(int i=0; i<N; i++)
{
int tmp;
scanf("%d",&tmp);
a[tmp]=1;
len1=max(len1,tmp);
}
len1++;
int len=1;
while(len < len1*2) len<<=1;
a[0]=1;
for(int i=0; i<len1; i++)
x1[i]=Complex(a[i],0);
for(int i=0; i<len1; i++)
x2[i]=Complex(a[i],0);
for(int i=len1; i<len; i++)
x2[i]=Complex(0,0);
fft(x1,len,1);
fft(x2,len,1);
for(int i=0; i<len; i++)
x1[i]=x1[i]*x2[i];
fft(x1,len,-1);
for(int i=0; i<len; i++)
sum[i]=(int)(x1[i].x+0.5);
scanf("%d",&M);
len=2*len1-1;
int cnt=0;
for(int i=0;i<M;i++)
{
int t;
scanf("%d",&t);
if(sum[t]>0) cnt++;
}
printf("%d\n",cnt);
}
return 0;
}
最新文章
- 【转】Handler学习笔记(一)
- 安装XDEBUG步骤及问题
- 锁屏上显示Activity
- an&#39;gularjs 环境搭建之NodeJS、NPM安装配置步骤(windows版本)
- GridView 分页方法
- Eclipse 复制按钮卡死
- 【poj2778-DNA Sequence】AC自动机+矩阵乘法
- 解决ligerUI服务器分页Total不起作用的问题
- grok 添加字段
- NavigationBar隐藏
- 【故障】MySQL主从同步故障-Slave_SQL_Running: No
- 开源微信管家平台——JeeWx 捷微4.0 微服务版本发布,全新架构,全新UI,提供强大的图文编辑器
- Tooltip导致的无法访问已释放对象
- 获取物料分类excel公式
- dbt 生产环境使用
- Eclipse 配置语言环境
- centos6编译安装zabbix3.0和中文支持整理文档
- python - 增强的格式化字符串format函数
- day21<;IO流+&;FIle递归>;
- 模拟退火算法(run away poj1379)