E - ∙ (Bullet)(组合数学)
思路:显然对于一组 只有两种情况, 同号或者异号, 存在0。
且要使 。显然是同号与异号进行组合。
且我们只需考虑 除去最大公因数 的组合.
因为 。
所以我们考虑储存同号的个数及对应异号的个数。(这里用 实现即可)
对于当前组 ,假设同号个数为 ,异号个数为 ,由于不能同时选同号和异号的,
显然我们可以只选同号或者只选异号的,这样有 种情况。
和 同时包含了当前组一个数不选的情况,所以要减去1.
即对于当前组的贡献为 .
所以根据乘法原理有:
1.显然当 中只有一个 时,等价于 与 进行组合,可以归为 .
2.当 时,因为它们不能与其他数共存,只能单独存在。所以对于这样的数贡献为
由于集合的非空性:所以还要减去所有组一个数都不选的情况
时间复杂度:
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
int n,cnt;
ll ksm(ll a,ll n){
ll ans=1;
while(n){
if(n&1) ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
int main(){
map<pair<ll,ll>,pair<int,int> >mp;
scanf("%d",&n);
for(int i=1;i<=n;i++){
ll a,b;
scanf("%lld%lld",&a,&b);
if(!a&&!b){
cnt++;
continue;
}
ll g=__gcd(a,b);
a/=g,b/=g;
if(b<0) a=-a,b=-b;//保证同号的时候都为正,异号的时候b恒为正.
if(a<=0) mp[{b,-a}].second++;//该组同号对应的异号个数.
else mp[{a,b}].first++; //该组同号个数
}
ll ans=1;
for(auto it:mp){
ans=(ans*(mod+ksm(2,it.second.first)+ksm(2,it.second.second)-1)%mod)%mod;//防止负数要+mod
}
printf("%lld\n",(mod+ans+cnt-1)%mod);
return 0;
}