2019上海网络赛 Triple (暴力+生成函数&FFT)

2019上海网络赛 Triple (暴力+生成函数&FFT)

题目大意

给出三组边A,B,C,从三组边中各选一条边,问有多少可以种做法可以组成三角形

解题思路

总共边的组合减去不能组成三角形的组合数就是答案。对于每组边种的每条边,统计剩余的两组边的和有多少对和大小小于自己,就是不合法的数量。对于剩余两组边的和的权值数组,在n<=1000的时候暴力统计,n>1000的时候生成函数FFT统计

AC代码

#include<bits/stdc++.h>
using namespace std;
const int size=2e5+5;
typedef long long LL;
int a[size],b[size],c[size];
int cnta[size],cntb[size],cntc[size];
LL sum[size];
int n;
namespace Polynomial_multiplication{
	const double pi=acos(-1);
	typedef complex<double> cp;
	int n, m, rev[size << 2];
	cp a[size << 2], b[size << 2];
	void init(int len) {
		for (n = 1, m = 0; n <= len; n <<= 1, m++);
		for (int i = 0; i < n; ++i) {
			rev[i] = rev[i >> 1] >> 1 | (i & 1) << (m - 1);
			a[i] = cp(0, 0);
			b[i] = cp(0, 0);
		}
	}
	void builda(vector<int> x,int len){for(int i=0;i<=len;i++) a[i]=cp(x[i],0);}
	void builda(int x[],int len){for(int i=0;i<=len;i++) a[i]=cp(x[i],0);}
	void buildb(vector<int> x,int len){for(int i=0;i<=len;i++) b[i]=cp(x[i],0);}
	void buildb(int x[],int len){for(int i=0;i<=len;i++) b[i]=cp(x[i],0);}
	void fft(cp *a, int f) {
		for (int i = 0; i < n; ++i)if (i < rev[i])swap(a[i], a[rev[i]]);
		for (int i = 1; i < n; i <<= 1) {
			double alpha = pi / i;
			if (f == -1)alpha = -pi / i;
			for (int k = 0; k < i; ++k) {
				cp w = cp(cos(alpha*k), sin(alpha*k));
				for (int j = k; j < n; j += (i << 1)) {
					cp x = w * a[j + i];
					a[j + i] = a[j] - x;
					a[j] += x;
				}
			}
		}
		if(f==-1) for(int i=0;i<n;i++) a[i]/=n;
	}
	void calc(vector<int> &v,int len) {
		fft(a, 1); fft(b, 1);
		for (int i = 0; i < n; ++i)a[i] *= b[i];
		fft(a, -1);
		for(int i=0;i<=len;i++) v.push_back(LL(a[i].real()+0.5));
	}
	void calc(LL v[],int len){
		fft(a,1),fft(b,1);
		for(int i=0;i<n;i++) a[i]*=b[i];
		fft(a,-1);
		for(int i=0;i<=len;i++) v[i]=LL(a[i].real()+0.5);
	}
} 
inline LL bruce(int x[],int y[],int z[])
{
	LL ans=0;
	for(int i=1;i<=z[n];i++) sum[i]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			sum[x[i]+y[j]]++;
		}
	}
	for(int i=1;i<=z[n];i++)
	{
		sum[i]=sum[i]+sum[i-1];
	}
	for(int i=1;i<=n;i++)
	{
		ans+=sum[z[i]-1];
	}
	return ans;
}
inline LL quick_solve(int x[],int y[],int z[])
{
	Polynomial_multiplication::init(2*z[n]+1);
	Polynomial_multiplication::builda(x,z[n]);
	Polynomial_multiplication::buildb(y,z[n]);
	Polynomial_multiplication::calc(sum,z[n]);
	for(int i=1;i<=z[n];i++)
	{
		sum[i]=sum[i]+sum[i-1];
	}
	LL ans=0;
	for(int i=1;i<=n;i++) ans+=sum[z[i]-1];
	return ans;
}
LL solve()
{
	LL  ans=1LL*n*n*n;
	if(n<=1000)
		return ans-bruce(a,b,c)-bruce(a,c,b)-bruce(b,c,a);	
	else 
	{
		memset(cnta,0,sizeof(cnta));
		memset(cntb,0,sizeof(cntb));
		memset(cntc,0,sizeof(cntc));
		for(int i=1;i<=n;i++)
		{
			cnta[a[i]]++;
			cntb[b[i]]++;
			cntc[c[i]]++;
		}
		return ans-quick_solve(cnta,cntb,c)-quick_solve(cntb,cntc,a)-quick_solve(cnta,cntc,b);
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	for(int kace=1;kace<=t;kace++)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);sort(a+1,a+1+n);
		for(int i=1;i<=n;i++) scanf("%d",&b[i]);sort(b+1,b+1+n);
		for(int i=1;i<=n;i++) scanf("%d",&c[i]);sort(c+1,c+1+n);
		printf("Case #%d: %lld\n",kace,solve());
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,我们需要明确三重梯形积分的定义和公式: $$\int_{x_0}^{x_n}\int_{y_0}^{y_m}\int_{z_0}^{z_l}f(x,y,z)dxdydz\approx\Delta x\Delta y\Delta z\sum_{i=0}^{n}\sum_{j=0}^{m}\sum_{k=0}^{l}f(x_i,y_j,z_k)$$ 其中,$\Delta x = \frac{x_n-x_0}{n}$,$\Delta y = \frac{y_m-y_0}{m}$,$\Delta z = \frac{z_l-z_0}{l}$,$x_i=x_0+i\Delta x$,$y_j=y_0+j\Delta y$,$z_k=z_0+k\Delta z$。 接下来,我们可以使用 PyTorch 搭建一个三层的神经网络来模拟三重梯形积分。具体代码如下: ``` import torch import torch.nn as nn class TripleIntegralNet(nn.Module): def __init__(self): super(TripleIntegralNet, self).__init__() self.fc1 = nn.Linear(3, 64) self.fc2 = nn.Linear(64, 128) self.fc3 = nn.Linear(128, 1) def forward(self, x): x = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) x = self.fc3(x) return x ``` 在这个神经网络中,我们使用了三个全连接层(fc1, fc2, fc3),其中输入的维度为 3,即 $(x_i, y_j, z_k)$,输出的维度为 1,即 $f(x_i, y_j, z_k)$ 的估计值。 接下来,我们可以使用这个神经网络来计算三重梯形积分的估计值。具体代码如下: ``` def triple_integral(f, x0, xn, y0, ym, z0, zl, n, m, l): delta_x = (xn - x0) / n delta_y = (ym - y0) / m delta_z = (zl - z0) / l integral = 0 net = TripleIntegralNet() for i in range(n+1): for j in range(m+1): for k in range(l+1): x = torch.tensor([x0+i*delta_x, y0+j*delta_y, z0+k*delta_z], dtype=torch.float32) integral += delta_x * delta_y * delta_z * net(x) return integral.item() ``` 在这个函数中,我们首先计算出 $\Delta x$,$\Delta y$ 和 $\Delta z$,然后创建一个三层神经网络(net),接着循环计算求和式中的每一项,最后返回积分的估计值。 最后,我们可以使用一个简单的函数来验证我们的神经网络是否正确模拟了三重梯形积分。具体代码如下: ``` def f(x, y, z): return torch.sin(x*y*z) x0, xn = 0, 1 y0, ym = 0, 2 z0, zl = 0, 3 n, m, l = 10, 20, 30 integral = triple_integral(f, x0, xn, y0, ym, z0, zl, n, m, l) print('integral:', integral) exact_integral = torch.tensor(1/6*(1-torch.cos(6)), dtype=torch.float32) print('exact integral:', exact_integral.item()) ``` 在这个函数中,我们定义了一个函数 $f(x,y,z)=\sin(xyz)$,然后计算了积分的精确值和估计值。最后,我们将它们打印出来并进行比较。如果我们的神经网络正确模拟了三重梯形积分,那么估计值应该非常接近于精确值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值