AtCoder Beginner Contest 168 E - ∙ (Bullet)

题目链接
思路:根据几种情况进行分类讨论
1.a=b=0:选了这个就不能选别的了。
2.a=0:这类数不能和 b=0的一起选
3.b=0:这类数不能和 a=0的一起选
4.other:
我们称满足x情况的数为第x类数。
具体:先将每个数的a,b取一下gcd化简一下。
然后枚举每个数被选的情况下,[1,i-1]有多少种合法选择使得不与i冲突。
设tot为[1,i-1]中第4类数的合法选择数。
那么如果第i个数属于第2类数,那么选了第i个之后,显然[1,i-1]中的第2类数可以选任意多个,第3类数只能选0个,第4类数选择方案为tot种,即为 t o t 2 c n t 2 tot*2^{cnt_2}
如果属于第3类数,同上。
如果属于第4类数:那么选择第i个数之后,第2,3类数的选择方案就有 2 c n t 2 + 2 c n t 3 1 2^{cnt_2}+2^{cnt_3}-1 种,理解为选任意多第2类数或任意多第3类数,但不同时选,再乘上tot就是包含这个的合法选择方案了。
最后来说tot是怎么维护的。
观察题目给定式子
A i A j + B i B j = 0 A_iA_j+B_iB_j=0 A i B i = B j A j \frac{A_i}{B_i}=-\frac{B_j}{A_j} 。我们称满足这个式子的两个最简分数匹配。
我们用一个map记录[1,i-1]中第i个分数的出现次数和和第i个分数匹配的分数的出现个数。那么之前tot中肯定包含有这组匹配分数的的一些选择方案,把这个去掉之后的tot就是不包含这组匹配分数的方案了,而第i个分数在[1,i-1]中可以随便选,那么总的方案就是 ( 2 c n t 2 + 2 c n t 3 1 ) t o t 2 c n t i (2^{cnt_2}+2^{cnt_3}-1)*tot*2^{cnt_i} ,最后再把第i个分数出现次数更新,再更新tot即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int n;
struct uzi{
	LL a,b;
}p[N];
const LL mod=1e9+7;
map<pair<LL,LL>,int>m;
LL pm(LL x,LL y){
	LL z=1;
	while(y){
		if(y&1)z=z*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return z;
}
LL fac[N];
int main() {
  ios::sync_with_stdio(false);
  cin>>n;
  fac[0]=1;
  for(int i=1;i<=n;i++)fac[i]=fac[i-1]*2%mod;
  for(int i=1;i<=n;i++){
  	cin>>p[i].a>>p[i].b;
  	LL z=__gcd(labs(p[i].a),labs(p[i].b));
  	if(z)p[i].a/=z;p[i].b/=z;
    if(p[i].b<0)p[i].b=-p[i].b,p[i].a=-p[i].a;
  }
  LL ans=0,tot=1;
	int npb=0,npa=0,gc=0,typ=0,dx=0,dy=0;
  for(int i=1;i<=n;i++){
    if(!p[i].a && !p[i].b) ans++;
    else if(!p[i].a){
      ans+=fac[npa]*tot%mod;
      ans%=mod;
      npa++;  
    }else if(!p[i].b){
      ans+=fac[npb]*tot%mod;
      ans%=mod;
      npb++;
    }else{
      int x=m[{p[i].a,p[i].b}];
      if(p[i].a<0)p[i].a=-p[i].a,p[i].b=-p[i].b;
      int y=m[{-p[i].b,p[i].a}];
      tot*=pm((fac[x]+fac[y]-1+mod)%mod,mod-2);
      tot%=mod;
      ans+=tot*fac[y]%mod*((fac[npa]+fac[npb]-1+mod)%mod)%mod;
      ans%=mod;
      m[{-p[i].b,p[i].a}]++;
      tot*=(fac[x]+fac[y+1]-1+mod)%mod;
      tot%=mod;
    }
  }
  cout<<ans<<'\n';
 	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40655981/article/details/106189849