首页 > 代码库 > 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; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。