1. 程式人生 > >HDU 2841 Visible Trees(容斥)題解

HDU 2841 Visible Trees(容斥)題解

color mod clu 問題 can scan 發現 質因數 get

題意:有一塊(1,1)到(m,n)的地,從(0,0)看能看到幾塊(如果兩塊地到看的地方三點一線,後面的地都看不到)。

思路:一開始是想不到容斥...後來發現被遮住的地都有一個特點,若(a,b)有gcd(a,b)!= 1,那麽就會被遮住。因為斜率k一樣,後面的點會被遮住,如果有gcd,那麽除一下就會變成gcd = 1的那個點的斜率了。所以問題轉化為求gcd不為1有幾個點,固定一個點,然後容斥。

#include<set>
#include<map>
#include<queue>
#include<cstdio>
#include<cstring>
#include
<iostream> #include<algorithm> #define ll long long using namespace std; const int maxn = 1000 + 10; const int seed = 131; const int MOD = 1000000000 + 7; const int INF = 0x3f3f3f3f; int prime[maxn], p[maxn], pn; int a[maxn], an; void get(){ memset(p, 0, sizeof(p)); pn = 0; for(ll i = 2; i < maxn; i++){
if(!p[i]){ prime[pn++] = i; for(ll j = i * i; j < maxn; j += i) p[j] = 1; } } } int main(){ int n, m; int T; get(); scanf("%d", &T); while(T--){ scanf("%d%d", &n, &m); ll ans = m; for(int i = 2
; i <= n; i++){ ll cnt = 0; //質因數分解 an = 0; int x = i; for(int j = 0; prime[j] * prime[j] <= x && j < pn; j++){ if(x % prime[j] == 0){ a[an++] = prime[j]; while(x % prime[j] == 0){ x /= prime[j]; } } } if(x > 1) a[an++] = x; //求gcd不為1 for(int j = 1; j < (1 << an); j++){ int num = 0; ll val = 1; for(int k = 0;k < an; k++){ if(j & (1 << k)){ num++; val *= a[k]; } } if(num & 1) cnt += m / val; else cnt -= m / val; } ans += m - cnt; } printf("%lld\n", ans); } return 0; }

HDU 2841 Visible Trees(容斥)題解