P3166 [CQOI2014]數三角形
阿新 • • 發佈:2018-11-19
可以考慮容斥,用三個點的總方案減去三點共線的情況。總的點數為\(t=(n+1)*(m+1)\),那麼總方案數就是\(C_t^3\)
考慮三點共線,我們列舉這條線段的兩個端點\((a,b),(x,y)\),那麼這條線段上的整點數就是\(gcd(x-a,y-b)-1\)
然而這樣複雜度太高。我們考慮優化,把\((a,b)\)給移到原點,那麼\((x,y)\)變成\((x-a,y-a)\),我們可以考慮列舉這個記做\((i,j)\),然後發現有很多條線段都可以平移成這樣,總的條數為\((n-i+1)*(m-j+1)\)
以上只是斜率大於等於\(0\)的情況。不難發現每一條斜率小於\(0\)
//minamoto #include<bits/stdc++.h> #define ll long long using namespace std; int n,m,gcd[1005][1005];ll ans,t; int GCD(int a,int b){ if(gcd[a][b])return gcd[a][b]; if(!a)return gcd[a][b]=b; if(!b)return gcd[a][b]=a; return gcd[a][b]=GCD(b,a%b); } void init(){ for(int i=1;i<=m;++i)gcd[0][i]=i; for(int i=1;i<=n;++i)gcd[i][0]=i; for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)GCD(i,j); } int main(){ scanf("%d%d",&n,&m),init(); t=(n+1)*(m+1),ans=t*(t-1)*(t-2)/6; for(int i=0;i<=n;++i)for(int j=0;j<=m;++j)if(i||j){ ans-=((!i||!j)?1ll:2ll)*(gcd[i][j]-1)*(n-i+1)*(m-j+1); } printf("%lld\n",ans);return 0; }