1621:轻拍牛头

1621:轻拍牛头原题(嵌入代码可能效果不好,请点链接看原题)

【题目描述】
原题来自:USACO 2008 Dec. Silver

今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏。

贝茜让 NN 头奶牛坐成一个圈。除了 11 号与 NN 号奶牛外,ii 号奶牛与 i−1i−1 号和 i+1i+1 号奶牛相邻,NN 号奶牛与 11 号奶牛相邻。农夫约翰用很多纸条装满了一个桶,每一张包含了一个 11 到 106106 的数字。

接着每一头奶牛 i 从桶中取出一张纸条 Ai ,每头奶牛轮流走一圈,同时拍打所有「编号是 AiAi 的约数」的牛,然后走回到原来的位置。牛们希望你帮助他们确定,每一头奶牛需要拍打的牛。

【输入】
第一行包含一个整数 NN;

接下来第二到第 N+1N+1 行每行包含一个整数 AiAi 。

【输出】
第一到第 N 行,第 i 行的输出表示第 i 头奶牛要拍打的牛数量。

【输入样例】
5
2
1
2
3
4
【输出样例】
2
0
2
1
3
【提示】
数据范围与提示:

对于全部数据,1≤N≤1051≤N≤105 。

【题意说明】

  对这个题目的描述,我觉得有点描述不清。”每头奶牛轮流走一圈,同时拍打所有[编号是Ai的约数]的牛“这里的编号指向不明确,如果是最初的1-N编号,显然样例数据不符。因为2号奶牛拿的数字是1,那它至少应该拍1号奶牛,但样例输出是0。查看另一篇博文https://www.luogu.com.cn/problem/P2926,描述为”每头奶牛轮流走上一圈,同时拍打所有手上数字能整除在自己纸条上的数字的牛的头“,这个描述很清楚,也符合样例数据,以下内容均按后者理解。

【分析】

  这个题目看起来并不难,判断一个数是否是另一个数的约数取余就可以了,要计算拍牛的次数,加一个计数器就OK。所以轻松搞定代码。

#include<iostream>
using namespace std;
int const N=1e6+5;
int a[N],ans[N],n;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)//枚举每一头牛
        for(int j=1;j<=n;j++)//其他牛的编号是否为当前牛编号的约数
            if(a[i]%a[j]==0)ans[i]++;
    for(int i=1;i<=n;i++)cout<<ans[i]-1<<endl;//ans[i]-1是要减去本身
    return 0;
}

  样例顺利通过,提交网站结果应该可以想到。这样都能通过是不是也太没水平了。简单算一个,对于百分之百的数据n<=10^5,一个双循环10^10,超时是必然的。

  在之前一个题1619:用到了筛选法可以优化时间复杂度,那我们也可以考虑用筛选法优化。我们不用把每一个编号都去验证,只把当前编号的倍数标记一次。那么每一头牛的编号由原来的验证其余牛的时间复杂度n可降为最大编号值/当前编号值。代码实现

//1621:轻拍牛头
#include<iostream>
using namespace std;
int const N=1e6+5;
int a[N],b[N],n,c[N],maxn=0;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        if(maxn<a[i])maxn=a[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=a[i];j<=maxn;j+=a[i])
            b[j]++;
    }
    for(int i=1;i<=n;i++)
        cout<<b[a[i]]-1<<endl;
    return 0;
}

  再次提交,46分,其余超时。想想一下,这个题数据量达到10^5,输入和输出应该占时较大,所以cin/cout的效率让我们不得不放入考虑范围,换吧,scanf/printf的效率可以提高不少,在前面博文中也有提及,特别是1205题就是一个很好例子。得以下代码

//1621:轻拍牛头
#include<cstdio>
int const N=1e6+5;
int a[N],b[N],n,maxn=0;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",a+i);
        if(maxn<a[i])maxn=a[i];
    }
    for(int i=1;i<=n;i++)
        for(int j=a[i];j<=maxn;j+=a[i])
            b[j]++;
    for(int i=1;i<=n;i++)
        printf("%d\n",b[a[i]]-1);
    return 0;
}

  再次提交,84分。这还能优化?必须啊,别人能过啊,那题肯定没问题啊。思考良久,想到一个地方:编号如果有重复,那我们验证时就会重复验证,特别编号又小,重复量再大一点,这一环节的效果更明显,再挤一挤吧。把重复项合并,只筛选一次就好。代码如下

//1621:轻拍牛头
#include<cstdio>
int const N=1e6+5;
int a[N],b[N],c[N],d[N][2],cnt,n,maxn,x;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",a+i);
        c[a[i]]++;
        if(maxn<a[i])maxn=a[i];
    }
    for(int i=1;i<=maxn;i++)
        if(c[i])d[++cnt][0]=i,d[cnt][1]=c[i];
    for(int i=1;i<=cnt;i++)
        for(int j=d[i][0];j<=maxn;j+=d[i][0])
            b[j]+=d[i][1];
    for(int i=1;i<=n;i++)
        printf("%d\n",b[a[i]]-1);
    return 0;
}

  再次提交:100分。终于AC了!

如果大家有更好看法,欢迎评论!!!

原文地址:https://www.cnblogs.com/wendcn/p/12620934.html

时间: 2024-10-13 15:28:57

1621:轻拍牛头的相关文章

一本通1621轻拍牛头

1621:轻拍牛头 时间限制: 1000 ms         内存限制: 524288 KB [题目描述] 原题来自:USACO 2008 Dec. Silver 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜让 N 头奶牛坐成一个圈.除了 1 号与 N 号奶牛外,i 号奶牛与 i?1 号和 i+1 号奶牛相邻,N 号奶牛与 1 号奶牛相邻.农夫约翰用很多纸条装满了一个桶,每一张包含了一个 1 到 106 的数字. 接着每一头奶牛 i 从桶中取出一张纸条 Ai ,每头奶牛轮

[BZOJ1607][Usaco2008 Dec]Patting Heads 轻拍牛头

1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 2590  Solved: 1361[Submit][Status][Discuss] Description 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜让N(1≤N≤100000)头奶牛坐成一个圈.除了1号与N号奶牛外,i号奶牛与i-l号和i+l号奶牛相邻.N号奶牛与1号奶牛相邻.农夫约翰用很多纸条装

BZOJ【1607】轻拍牛头

1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 1245  Solved: 650[Submit][Status][Discuss] Description 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜让N(1≤N≤100000)头奶牛坐成一个圈.除了1号与N号奶牛外,i号奶牛与i-l号和i+l号奶牛相邻.N号奶牛与1号奶牛相邻.农夫约翰用很多纸条装满

bzoj1607:轻拍牛头

1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 1162  Solved: 602[Submit][Status][Discuss] Description 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜让N(1≤N≤100000)头奶牛坐成一个圈.除了1号与N号奶牛外,i号奶牛与i-l号和i+l号奶牛相邻.N号奶牛与1号奶牛相邻.农夫约翰用很多纸条装满

[bzoj 1607] [Usaco2008 Dec]Patting Heads 轻拍牛头 筛数

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1607 1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 Time Limit: 3 Sec Memory Limit: 64 MB Submit: 1654 Solved: 874 [Submit][Status][Discuss] Description 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜让N(1≤N≤100000)头奶牛坐成一

BZOJ 1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 筛法

1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1607 Description 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜让N(1≤N≤100000)头奶牛坐成一个圈.除了1号与N号奶牛外,i号奶牛与i-l号和i+l号奶牛相邻.N号奶牛与1号奶牛相邻.农夫

【BZOJ】1607: [Usaco2008 Dec]Patting Heads 轻拍牛头

[算法]模拟 #include<cstdio> #include<algorithm> using namespace std; const int maxn=100010,maxm=1000010; int a[maxn],A[maxm],n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); A[a[i]]++; } for

bzoj 1607: [Usaco2008 Dec]Patting Heads 轻拍牛头

翻过来考虑影响,考虑多少数是他的倍数. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 #include<vector> 9 #define M 1000009 10 #define

[BZOJ1607] [Usaco2008 Dec] Patting Heads 轻拍牛头 (数学)

Description 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜让N(1≤N≤100000)头奶牛坐成一个圈.除了1号与N号奶牛外,i号奶牛与i-l号和i+l号奶牛相邻.N号奶牛与1号奶牛相邻.农夫约翰用很多纸条装满了一个桶,每一张包含了一个独一无二的1到1,000,000的数字. 接着每一头奶牛i从柄中取出一张纸条Ai.每头奶牛轮流走上一圈,同时拍打所有手上数字能整除在自己纸条上的数字的牛的头,然后做回到原来的位置.牛们希望你帮助他们确定,每一头奶牛需要拍打的牛. I