现在的位置: 首页 > 综合 > 正文

hdu 2841 Visible Trees【容斥原理】

2015年12月18日 ⁄ 综合 ⁄ 共 1935字 ⁄ 字号 评论关闭

Visible Trees

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1602    Accepted Submission(s): 661

Problem Description
There are many trees forming a m * n grid, the grid starts from (1,1). Farmer Sherlock is standing at (0,0) point. He wonders how many trees he can see.

If two trees and Sherlock are in one line, Farmer Sherlock can only see the tree nearest to him.

 

Input
The first line contains one integer t, represents the number of test cases. Then there are multiple test cases. For each test case there is one line containing two integers m and n(1 ≤ m, n ≤ 100000)
 

Output
For each test case output one line represents the number of trees Farmer Sherlock can see.
 

Sample Input
2 1 1 2 3
Sample Output
1 5
题目翻译:给你一个(m,n)的矩阵,每个点上有一颗树,你站在(0,0)点看矩阵,前面的树会挡着后面的树,问你此时一共可以看到多少树!
结题思路:由于是站在(0,0),因此此时被挡的那棵树(X,Y)和挡它的那棵树(x,y)有一些关系,此时和(0,0)三点共线,因此X / x == Y / y;
因此(X,Y)必有公约数,因此点任意一点(A,B)只要A,B有约数,则一定看不到,反之,A,B互质则一定可以看到,因此问题转化为求图中的互质点对;
说到求互质,第一想起来的就是gcd,但是gcd求起来必然耗时,因此可以用容斥原理,前面的博客已经介绍了利用容斥原理求M和1-N中有多少互质,那么现在是求1-M中的所有数与1-N中有多少互质,因此循环1—N即可!
#include<cstdio>
#define LL long long
int p[10],top;
void getp(int v){
    top=0;
    for(int i=2;i*i<=v;i++){
        if(v%i==0){
            p[top++]=i;
            while(v%i==0) v/=i;
        }
    }
    if(v>1)p[top++]=v;
}
LL nop(int n,int t){
    int i;
    LL num=0;
    for(i=t;i<top;i++)
        num+=n/p[i]-nop(n/p[i],i+1);
    return num;
}
int main(){
    int t,m,n,i;
    LL sum;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&m,&n);
        sum=n;
        for(i=2;i<=m;i++){
            getp(i);
            sum+=(n-nop(n,0));
        }
        printf("%lld\n",sum);
    }
}

说实话代码超短,但是还是WA了3次,原因很简单,nop忘了写返回值,而且getp函数中,把while误写成if,真不知道自己写代码的时候想的啥,过了一天静下心来才改对

翻别人的博客,发现直接进行预处理素数表,可以省一部分时间,但是耗内存,下面贴代码

#include<cstdio>
#define LL long long
int prime[100005][20];
int cnt[100005]={0};
void Init(){
    for(int i=2;i<=100000;i++){
        if(cnt[i]) continue;
        prime[i][0]=i;
        cnt[i]=1;
        for(int j=2;j*i<=100000;j++)
            prime[i*j][cnt[i*j]++]=i;
    }
}
LL dfs(int m,int n,int idx){
    LL ret=0;
    for(int i=idx;i<cnt[m];i++)
        ret+=n/prime[m][i]-dfs(m,n/prime[m][i],i+1);
    return ret;
}
int main(){
    Init();
    int t,n,m;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        LL ans=n;
        for(int i=2;i<=m;i++)
            ans+=(n-dfs(i,n,0));
        printf("%I64d\n",ans);
    }
    return 0;
}

抱歉!评论已关闭.