GJGHFD的蛇 题解 [容斥]

GJGHFD的蛇

Description:

​ GJGHFD 的农田中有 \(n\) 条蛇,第 \(i\) 条蛇位于位置 \((x_i, y_i)\) ,并且具有一个危险度 \(b_i\). 现在,GJGHFD 手中有 m 把枪,他决定给每把枪指定一条蛇作为目标,并且每把枪的目标互不相同. 指定目标后,这 \(m\) 把枪就会同时开枪.
​ 对于一个指定目标的方案,在 GJGHFD 开枪后,第 \(i\) 条蛇被影响到当且仅当有一把枪指向它,或者有一把枪指向 \(j\) ,并且 \(\max(|x_i−x_j |, |y_i−y_j |) \leq r\),其中 \(r\) 是这 \(m\) 把枪的共有属性. 如果第 \(i\) 条蛇被影响到,则 GJGHFD 将获得分数 \(b_i\). 这些分数之和就是此方案的总得分. 求所有指定目标的方案的总得分的平方和.
​ 因为答案可能较大,请输出其对 \(10^9 + 7\) 取模的结果.

Input:

​ 第一行三个整数 \(n, m, r\) .
​ 接下来 \(n\) 行,每行三个整数 \(x_i, y_i, b_i\) ,描述一条蛇.

Output:

​ 一行一个整数表示答案.

Sample Input:

4 2 1
1 1 10
2 2 20
2 3 30
5 2 40

Sample Output:

33800

Hint:

​ 对于\(20\%\)的数据,\(1 \leq m \leq n \leq 10\)

​ 对于\(50\%\)的数据,\(1 \leq m \leq n \leq 200\)

​ 对于\(100\%\)的数据,\(1 \leq m \leq n \leq 3 \times 10^3,0 \leq r < 10^{3},1 \leq x_i,y_i \leq 10^3,1 \leq b_i \leq 10^6\)

​ 时间限制: \(1s\)

​ 空间限制: \(512M\)

题目分析:

​ 设选出的m条蛇所能影响到的所有蛇的集合为\(\begin{Bmatrix}b_1,b_2,...,b_k\end{Bmatrix}\).

​ 我们可以把\((\sum_{i=1}^kb_{p_i})^2\)可以拆成:\(\sum_{i=1}^k \sum_{j=1}^k b_{p_i} \times b_{p_j}\).

​ 于是我们可以想到给每一对\(b_i \times b_j\)计算贡献,然后求个和即可。

​ 我们设两条蛇\(i,j\)在一种方案中都被影响到的可能方案数为\(x\).

​ 我们考虑容斥,设 \(a=\) 选中之后只能影响\(i\),不能影响\(j\)的蛇的个数, \(b=\) 选中之后不能影响\(i\),只能影响\(j\)的蛇的个数, \(c=\) 选中之后既能影响\(i\),又能影响\(j\)的蛇的个数.

​ 则\(x=C_n^m-C_{n-a-c}^m-C_{n-b-c}^m+C_{n-a-b-c}^m\)

​ 即:总方案\(-\)不合法方案.

​ 而\(a,b,c\)可以通过预处理前缀和\(O(1)\)计算,于是我们可以用\(O(n^2)\)的复杂度过了此题。

​ 代码如下(马蜂很丑,不喜勿喷)——

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define Tp template<typename T>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define maxn 3005
#define LL long long
using namespace std;
int n,m,r,x[maxn],y[maxn],v[maxn],ans,maxx,maxy,f[maxn][maxn],sum[maxn][maxn];const int p=1e9+7;
inline int S(int sx,int sy,int tx,int ty){sx=max(1,sx);tx=min(maxx,tx);sy=max(1,sy);ty=min(maxy,ty);if(sx>tx||sy>ty) return 0;return sum[tx][ty]-sum[sx-1][ty]-sum[tx][sy-1]+sum[sx-1][sy-1];}
inline int calc(int a,int b,int c){int x=f[n][m]-f[n-a-c][m];(x<0)&&(x+=p);x-=f[n-b-c][m],(x<0)&&(x+=p);x+=f[n-a-b-c][m];(x>=p)&&(x-=p);return x;}
class FileInputOutput
{
	private:
		static const int S=1<<21;
		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
		#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
		char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
	public:
		FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
		Tp inline void read(T& x)
		{
			x=0; char ch; while (!isdigit(ch=tc()));
			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
		}
		Tp inline void write(T x,const char& ch)
		{
			if (x<0) pc('-'),x=-x; RI ptop=0; while (pt[++ptop]=x%10,x/=10);
			while (ptop) pc(pt[ptop--]+48); pc(ch);
		}
		inline void flush(void)
		{
			fwrite(Fout,1,Ftop-Fout,stdout);
		}
		#undef tc
		#undef pc
}F;
int main(){
//	freopen("data2.in","r",stdin);
	F.read(n),F.read(m),F.read(r);for(register int i=1;i<=n;i++) F.read(x[i]),F.read(y[i]),F.read(v[i]),sum[x[i]][y[i]]++,maxx=max(maxx,x[i]),maxy=max(maxy,y[i]);
	for(register int i=1;i<=maxx;i++) for(register int j=1;j<=maxy;j++) sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
	f[0][0]=1;for(register int i=1;i<=n;i++){f[i][0]=1;for(register int j=1;j<=m;j++) f[i][j]=f[i-1][j]+f[i-1][j-1],(f[i][j]>=p)&&(f[i][j]-=p);}
	for(register int i=1,xx;i<=n;i++) xx=f[n][m]-f[n-S(x[i]-r,y[i]-r,x[i]+r,y[i]+r)][m],(xx<0)&&(xx+=p),ans+=1ll*xx*v[i]%p*v[i]%p,(ans>=p)&&(ans-=p);
	for(register int i=1;i<n;i++) for(register int j=i+1;j<=n;j++){
		int c=S(max(x[i]-r,x[j]-r),max(y[i]-r,y[j]-r),min(x[i]+r,x[j]+r),min(y[i]+r,y[j]+r)),a=S(x[i]-r,y[i]-r,x[i]+r,y[i]+r)-c,b=S(x[j]-r,y[j]-r,x[j]+r,y[j]+r)-c;
		ans+=2ll*calc(a,b,c)*v[i]%p*v[j]%p;(ans>=p)&&(ans-=p);
	}
	F.write(ans,'\n');return F.flush(),0;
}

posted @ 2021-01-05 20:13  OdtreePrince  阅读(131)  评论(0编辑  收藏  举报