farm - 容斥

题目大意:令 F ( a , b ) F(a,b) F(a,b)表示是否存在一个点 ( x , y ) (x,y) (x,y)使得其和 ( a , 0 ) , ( 0 , b ) (a,0),(0,b) (a,0),(0,b)围成的三角形面积是s。求 ∑ a = 1 m F ( a , n ) + ∑ b = 1 n F ( 0 , b ) \sum_{a=1}^mF(a,n)+\sum_{b=1}^nF(0,b) a=1mF(a,n)+b=1nF(0,b)。1000组数据, n = n 1 n 2 n 3 n=n_1n_2n_3 n=n1n2n3,m和s同理, n i , m i , s i ≤ 1 0 6 n_i,m_i,s_i\le10^6 ni,mi,si106
题解:首先显然F(0,b)为1当且仅当b|(2s),所以 ∑ b = 1 n F ( 0 , b ) \sum_{b=1}^nF(0,b) b=1nF(0,b)等于2s(下文中记作S)的小于等于b的因数个数。爆搜S的因数即可。
然后我们考虑若F(a,b)有解,当且仅当至少一个点会落在 y = − b a x + S a + b y=-\frac{b}{a}x+\frac{S}{a}+b y=abx+aS+b上,因此 a ∣ ( S − b x ) a|(S-bx) a(Sbx),即 ∃ y , b x + a y = S ⇒ ( a , b ) ∣ S \exist y,bx+ay=S\Rightarrow (a,b)|S y,bx+ay=S(a,b)S。即这部分答案是: ∑ a = 1 m F ( a , n ) = ∑ a = 1 m [ ( a , n ) ∣ S ] \sum_{a=1}^mF(a,n)=\sum_{a=1}^m[(a,n)|S] a=1mF(a,n)=a=1m[(a,n)S]。注意到 ( a , n ) ∣ S (a,n)|S (a,n)S等价于,设质数 p p p n n n中指数 n i n_i ni,在 S S S指数 S i S_i Si,那么若 n i > S i n_i>S_i ni>Si,则 p p p a a a中指数 a i ≤ s i a_i\le s_i aisi。注意到这玩意可以容斥,并且由于前16小的质数乘积就爆 1 0 18 10^{18} 1018了,因此复杂度是对的。

 
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
using namespace std;typedef pair<int,int> pii;const int N=1000000+2;int p[N],mnp[N],np[N];
inline int inn() { int x,ch;while((ch=gc)<'0'||ch>'9');x=ch^'0';while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
inline int prelude(int n) { for(int i=2,c=0;i<=n;i++) { if(!np[i]) p[++c]=i,mnp[i]=i;rep(j,1,c&&p[j]<=n/i) { int x=p[j]*i;np[x]=1,mnp[x]=p[j];if(i%p[j]==0) break; } } return 0; }
struct Int{
    int vis[N],cnt;pii v[20];lint val[20];inline int init() { rep(i,1,cnt) vis[v[i].fir]=0;return cnt=0; }
    inline lint value()const { lint x=1;rep(i,1,cnt) x*=val[i];return x; }
    inline int add(int x) { for(int t;(t=mnp[x]);) { if(!vis[t]) vis[t]=++cnt,v[cnt]=mp(t,0),val[cnt]=1;int p=vis[t];while(x%t==0) x/=t,v[p].sec++,val[p]*=t; } return 0; }
    inline lint dfs(int x,lint s,lint n)const { if(x==cnt+1) return s<=n;if(s>n) return 0;lint ans=0;rep(j,0,v[x].sec) if(s<=n) ans+=dfs(x+1,s,n),s*=v[x].fir;else break;return ans; }
    inline int getcnt(int x)const { if(!vis[x]) return 0;return v[vis[x]].sec; }
    inline lint qwq(int x)const { if(!vis[x]) return x;return x*val[vis[x]]; }
}n,m,s;
namespace SOLVE1_space{
    const int S=(1<<16)+2;lint xz[20],val[S];int sz[S],id[S];
    inline lint solve(const Int &n,lint m,const Int &s)
    {
        int cnt=0;rep(i,1,n.cnt) if(n.v[i].sec>s.getcnt(n.v[i].fir)) xz[cnt++]=s.qwq(n.v[i].fir);
        int all=(1<<cnt)-1;lint ans=0;val[0]=1;rep(i,0,cnt-1) id[1<<i]=i;
        rep(i,1,all) sz[i]=sz[i>>1]+(i&1),val[i]=val[i^(i&(-i))]*xz[id[i&-i]];
        rep(i,0,all) if(sz[i]&1) ans-=m/val[i];else ans+=m/val[i];return ans;
    }
}
namespace SOLVE2_space{ inline lint solve(lint n,const Int &s) { return s.dfs(1,1,n); } }
int main()
{
    prelude(N-1);
    for(int T=inn();T;T--)
    {
        n.init(),m.init(),s.init();rep(i,0,2) n.add(inn());rep(i,0,2) m.add(inn());rep(i,0,2) s.add(inn());s.add(2);
        printf("%lld\n",SOLVE1_space::solve(n,m.value(),s)+SOLVE2_space::solve(n.value(),s));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值