首页 > 代码库 > ACdream oj C - 神奇的%系列一 (水题系列--略坑)

ACdream oj C - 神奇的%系列一 (水题系列--略坑)



C - 神奇的%系列一

Time Limit: 6000/3000 MS (Java/Others)      Memory Limit: 65536/32768 KB (Java/Others) 
Submit Status

Problem Description

在计算机的世界里,%不是百分比,而是除法取余哟!
比如:
  4 % 2 = 0
  5 % 3 = 2

给你 2<=N<=100000 个数,a[1],a[2]...a[i]...a[n]。
其中:1<=a[i]<=100000。

问有几个组合 ( a[i] , a[j] ),(其中i!=j,且a[i]>a[j]),
使得 a[i] % a[j] != 0。

Input

输入有多组数据,对于每组数据:(T<=30)
第一行:N(表示N个数)
第二行:N个元素 a[i]  

Output

输出有几个组合(a[i],a[j]),使得a[i] % a[j] != 0

Sample Input

3
1 1 1
4
1 2 3 4
5
1 2 2 4 6

Sample Output

0
2
1

这个题那天晚上想了好久,一开始看到这个题觉得可以做,脑海中浮现出来的是最朴素的算法,开始没想那么多,没去计算时间复杂度之类的,几分钟就把程序写好了,提交上去。。。果不奇然,超时了(后面粗略的一算,O(n2)100000*100000,肯定会超时的啊。。。)比赛的时候一定不能乱提交啊!!!!

下面是朴素的算法(暴力)

#include<stdio.h>
#define N 100001
typedef long long LL;
LL a[N];
int main()
{
    int n,i,j;
   while(scanf("%d",&n)!=EOF)
    {
    for(i=1;i<=n;i++)
        scanf("%I64d",&a[i]);
       LL ret2=0;
    for(i=1;i<=n;i++) {
          for(j=i+1;j<=n;j++) {
             if(a[i]>a[j])
                {
                 if(a[i]%a[j]!=0) ret2++;
                }
           else if(a[j]>a[i])
                {
                 if(a[j]%a[i]!=0) ret2++;
                }

            }
        }
       printf("%I64d\n",ret2);
    }
       return 0;
}

直接一个二重循环去搜索!!(这样的效率真心低,以后尽量不要这样写)

后来就一直在想优化的方法,一直想不出啊!!!大哭,当时也想了可以用近似于筛选法的思路,今天看了一下别人的思路,顿时茅塞顿开啊~。

这道题的主要思路是算组合数,题目中问我们是有多少个组合,2个数的总的组合数是Cn 2=n*(n-1)/2;

我们就拿总的组合数减去a[i]/a[j]=0的组合数 ,(中间有组合数相同的情况a[i]/a[i]);

下面是ac的代码;

#include <stdio.h>
#include <string.h>
#define N 100005
int a[N];
long long count[N];//记录a[i] 出现的次数;
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(count,0,sizeof(count));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            count[a[i]]++;
        }
        long long sum=((long long )n*(long long )(n-1))/2;//总的组合数;
        for(int i=1;i<=100000;i++)
        {
            if(count[i]==0) continue;//剪枝
            sum-=((count[i])*(count[i]-1))/2;//取余的组合数相等的情况;
            for(int j=i+i;j<=100000;j+=i)
            {
                sum-=count[i]*count[j];
            }
        }
        printf("%lld\n",sum);//这里最坑爹了,不知道是不是他系统的问题,开始用的是I64d,提交了10多次全都是wa,改成lld立马就a了。。。
    }
    return 0;
}