1.桶排序统计相同数值的数量 计算约数
ybt
通过
测试点 | 结果 | 内存 | 时间 |
测试点1 | 答案正确 | 616KB | 2MS |
测试点2 | 答案正确 | 620KB | 2MS |
测试点3 | 答案正确 | 612KB | 1MS |
测试点4 | 答案正确 | 616KB | 1MS |
测试点5 | 答案正确 | 624KB | 2MS |
测试点6 | 答案正确 | 692KB | 4MS |
测试点7 | 答案正确 | 1112KB | 24MS |
测试点8 | 答案正确 | 4716KB | 116MS |
测试点9 | 答案正确 | 1400KB | 26MS |
测试点10 | 答案正确 | 4912KB | 50MS |
测试点11 | 答案正确 | 4896KB | 35MS |
测试点12 | 答案正确 | 1404KB | 89MS |
测试点13 | 答案正确 | 1412KB | 90MS |
LOJ
LUOGU
书上的翻译好烂,一直看不懂,看了在线测评的上述3个OJ,发现题意有改进,一看,就能看懂,我的天,书没用啊,耽搁了好长时间.
补充题意如下:
接着每一头奶牛i从桶中取出一张纸条Ai ,每头奶牛轮流走一圈,同时拍打所有「抽到字条数字是Ai的因数」的牛,然后走回到原来的位置。
样例解释如下:
输入:
5
2
1
2
3
4
输出:
2
0
2
1
3
a[i]表示序号为i的牛抽到的数字
a[1]=2能整除a[2]=1,a[3]=2 共2个数字
a[2]=1不能整除其它4头牛手上的数字,故输出0
a[3]=2能整除a[1]=2,a[2]=1 共2个数字
a[4]=3能整除a[2]=1 共1个数字
a[5]=4能整除a[1]=2,a[2]=1,a[3]=2 共3个数字
按暴力每头牛枚举其它所有的牛,计算次数是10^5*10^5=10^10 超时是显然的.
目前思路,用桶排序,记录抽到数字的数量,具体到每头牛的数字找因数时,采用枚举约数的方式,进行查找,这样在N=10^5,数字是10^6,极端情况下计算次数是sqrt(10^6)*10^5=10^8,感觉超时无疑,试试吧。提交AC,数据太水了吧。
桶排序统计相同数值的数量 计算约数 代码如下:
#include <bits/stdc++.h>
#define maxn 1000010
using namespace std;
int a[maxn],b[maxn];//b[a[i]]用来统计a[i]相同数值的数量
int main(){
int i,j,n,cnt;
scanf("%d",&n);
for(i=1;i<=n;i++)b[i]=0;
for(i=1;i<=n;i++)scanf("%d",&a[i]),b[a[i]]++;
for(i=1;i<=n;i++){
for(j=1,cnt=0;j*j<=a[i];j++){
if(a[i]%j==0){//j是一个约数
if(b[j])cnt+=b[j];
if(a[i]/j!=j){//a[i]/j是另一个约数
if(b[a[i]/j])cnt+=b[a[i]/j];
}
}
}
cnt--;//计算过程中,一定会把自己算进,故要减去1
printf("%d\n",cnt);
}
return 0;
}
2.筛法的思想
ybt
通过
测试点 | 结果 | 内存 | 时间 |
测试点1 | 答案正确 | 8436KB | 48MS |
测试点2 | 答案正确 | 8432KB | 44MS |
测试点3 | 答案正确 | 8424KB | 46MS |
测试点4 | 答案正确 | 8424KB | 45MS |
测试点5 | 答案正确 | 8432KB | 45MS |
测试点6 | 答案正确 | 8448KB | 48MS |
测试点7 | 答案正确 | 8524KB | 49MS |
测试点8 | 答案正确 | 8620KB | 54MS |
测试点9 | 答案正确 | 8816KB | 62MS |
测试点10 | 答案正确 | 8820KB | 63MS |
测试点11 | 答案正确 | 8820KB | 61MS |
测试点12 | 答案正确 | 8820KB | 61MS |
测试点13 | 答案正确 | 8816KB | 63MS |
LOJ
LUOGU
针对样例(可以对着下面的AC代码进行理解)展示筛法的思想
在[1,8]区间,进行筛法
a[1]=2
a[2]=1
a[3]=2
a[4]=3
a[5]=4
b[1]=1,b[2]=2,b[3]=1,b[4]=1
进行筛法
考虑b[1]=1
c[1]=1,c[2]=1,c[3]=1,c[4]=1,c[5]=1,c[6]=1,c[7]=1,c[8]=1
考虑b[2]=2
c[2]=3,c[4]=3,c[6]=3,c[8]=3
考虑b[3]=1
c[3]=2,c[6]=4
考虑b[4]=1
c[4]=4,c[8]=4
综合以上,最终
c[1]=1,c[2]=3,c[3]=2,c[4]=4,c[5]=1,c[6]=4,c[7]=1,c[8]=4
a[1]=2 对应c[2]=3 扣除自身重复统计,值为3-1=2
a[2]=1 对应c[1]=1 扣除自身重复统计,值为1-1=0
a[3]=2 对应c[2]=3 扣除自身重复统计,值为3-1=2
a[4]=3 对应c[3]=2 扣除自身重复统计,值为2-1=1
a[5]=4 对应c[4]=4 扣除自身重复统计,值为4-1=3
在N=10^5,数字是10^6,极端情况下计算次数,编码如下:
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,a,i;
long long cnt=0;
scanf("%d%d",&n,&a);
for(i=1;i<=a;i++)cnt+=a/i;
printf("cnt=%lld\n",cnt);
return 0;
}
上述代码对应的输入输出数据如下:
100000 1000000
cnt=13970034
极端计算次数是cnt=13970034也即1.4*10^7
n/1+n/2+n/3......+n/n-1
=∑n/x dx
=n*lnx
范围是(1,n-1)
所以=n*ln(n-1)
10^6*ln(10^6)=13815511也即1.4*10^7与上述代码计算基本吻合。
筛法的思想 AC代码如下:
#include <bits/stdc++.h>
#define maxn 1000010
using namespace std;
int a[maxn],b[maxn],c[maxn];//b[a[i]]用来统计a[i]相同数值的数量
int main(){
int i,j,n,cnt;
scanf("%d",&n);
for(i=1;i<=n;i++)b[i]=0,c[i]=0;//c[i]用来统计有效约数个数
for(i=1;i<=n;i++)scanf("%d",&a[i]),b[a[i]]++;
for(i=1;i<=1000000;i++)//筛法的思想
for(j=i;j<=1000000;j+=i)
c[j]+=b[i];
for(i=1;i<=n;i++)printf("%d\n",c[a[i]]-1);//扣掉自身
return 0;
}
3.避免空算 筛法的思想
ybt
通过
测试点 | 结果 | 内存 | 时间 |
测试点1 | 答案正确 | 8428KB | 8MS |
测试点2 | 答案正确 | 8428KB | 6MS |
测试点3 | 答案正确 | 8428KB | 8MS |
测试点4 | 答案正确 | 8428KB | 9MS |
测试点5 | 答案正确 | 8432KB | 12MS |
测试点6 | 答案正确 | 8448KB | 15MS |
测试点7 | 答案正确 | 8524KB | 18MS |
测试点8 | 答案正确 | 8628KB | 18MS |
测试点9 | 答案正确 | 8812KB | 43MS |
测试点10 | 答案正确 | 8812KB | 38MS |
测试点11 | 答案正确 | 8812KB | 29MS |
测试点12 | 答案正确 | 8816KB | 61MS |
测试点13 | 答案正确 | 8820KB | 60MS |
LOJ
LUOGU
避免空算 筛法的思想 AC代码如下:
#include <bits/stdc++.h>
#define maxn 1000010
using namespace std;
int a[maxn],b[maxn],c[maxn];//b[a[i]]用来统计a[i]相同数值的数量
int main(){
int i,j,n,cnt;
scanf("%d",&n);
for(i=1;i<=n;i++)b[i]=0,c[i]=0;//c[i]用来统计有效约数个数
for(i=1;i<=n;i++)scanf("%d",&a[i]),b[a[i]]++;
for(i=1;i<=1000000;i++)//筛法的思想
if(b[i]) //避免空算
for(j=i;j<=1000000;j+=i)
c[j]+=b[i];
for(i=1;i<=n;i++)printf("%d\n",c[a[i]]-1);//扣掉自身
return 0;
}
该题的收获:筛法的思想(以前从未应用过)。