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; }