Good Bye 2018 C. New Year and the Sphere Transmission(GCD相关)

 

传送门

https://www.cnblogs.com/violet-acmer/p/10201535.html

 

题意

  $n$ 个 $people$,编号 $1,2,3,\cdots ,n$ ,按顺时针方向围城一圈;

  初始,编号为 $1$ 的 $people$ 抱着一个球,他可以将球顺时针传给他左手边的第 $k$ 个 $people$;

  接到球的 $people$ 依次将球传给他顺时针方向的第 $k$ 个 $people$;

  循环进行,直到球再一次落到 $1$ 号 $people$ 手中,结束;

  定义一个开心值 :所有接到球的 $people$ 的编号和。

  求所有的开心值,并按升序排列。

题解

  弱弱的我只能通过打表找规律%%%%%%%那些一眼看出规律的大神们 

  $\begin{aligned} k &= 1\rightarrow 1 \\ k&= 2\rightarrow 1,3 \\ k&= 3\rightarrow 1,6 \\ k&= 4\rightarrow 1,4,10 \\ k&= 5\rightarrow 1,15 \\ k&= 6\rightarrow 1,5,9,21 \\ k&= 7\rightarrow 1,28\end{aligned}$

  刚开始,发现,有些数的开心值只有两个,然后,把这些只有两个开心值的数列了一下,发现,全是素数。

  不知为啥,求了一下每个数的因子个数,发现没,开心值的个数与他们的因子个数有关!!!

  然后,在草纸上列出了前 12 项的答案,找了一下规律,哇,最后10分钟,找到了一个前10个通用的规律。

  最后结束时刻提交,emmmmm,wa

  然后,睡觉,哈哈哈。

  今天,把昨天的错误数据看了一下,重新找了一下规律

  emmmm,找到了

  以 $k=15$ 为例:

    $15$ 的因子为 $1,3,5,15$

    开心值为 $1,18,35,120$

    1=1;

    18=1+6+11;                    //d=5,tot=3

    35=1+4+7+10+13;                   //d=3,tot=5

    120=1+2+3+4+5+6+7+8+9+10+11+12+13+14+15;         //d=1,tot=15

  发现没,开心值就是以 $15$ 的因子为公差的前 $tot$ 项和;

•Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define ll __int64
 8 #define mem(a,b) memset(a,b,sizeof(a))
 9 const int maxn=1e6+10;
10 
11 ll n;
12 ll a[maxn];
13 ll res[maxn];
14 
15 int factor()//求出n的所有因子
16 {
17     int x=sqrt(n);
18     a[1]=1;
19     int index=1;
20     for(int i=2;i <= x;++i)
21     {
22         if(n%i == 0)
23         {
24             a[++index]=i;
25             if(n/i != i)
26                 a[++index]=n/i;
27         }
28     }
29     a[++index]=n;
30     return index;
31 }
32 int main()
33 {
34     scanf("%d",&n);
35     int t=factor();
36     sort(a+1,a+t+1);
37     for(int i=1;i <= t;++i)
38     {
39         ll d=a[i],tot=n/d;
40         ll a1=1,an=a1+(tot-1)*d;
41         res[i]=tot*(a1+an)/2;
42     }
43     for(int i=t;i >= 1;--i)
44         printf("%I64d ",res[i]);
45 }
View Code

•打表找规律代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 #define ll __int64
 7 #define mem(a,b) memset(a,b,sizeof(a))
 8 const ll MOD=998244353;
 9 const int maxn=1e6+10;
10 
11 int n;
12 int a[maxn];
13 
14 int main()
15 {
16     for(int i=1;i <= 15;++i)
17     {
18         i=15;
19         int tot=0;
20         for(int k=1;k <= i;++k)
21         {
22             int res=1;
23             int index=1+k;
24             printf("****\nk=%d\n",k);
25             printf("1");
26             while(index != 1)
27             {
28                 if(index > i)
29                     index %= i;
30                 if(index == 1)
31                     break;
32                 res += index;
33                 printf("+%d",index);
34                 index += k;
35             }
36             printf("=%d\n",res);
37             a[tot++]=res;
38         }
39 
40         sort(a,a+tot);
41         int t=unique(a,a+tot)-a;
42         printf("\n===========\ni=%d\n",i);
43         for(int j=0;j < t;++j)
44             printf("%d ",a[j]);
45         break;
46     }
47 }
48 //1 27 105 235 625 1275
View Code

 


分割线2019.6.14

感悟

  因打表找规律而AC的题,不能当作正解,赛后补题,要花时间思考正解;

•想法

  从编号为 $1$ 的 $people$ 开始传球,依次传给其顺时针方向的第 $k$ 个人;

  可以肯定的是,球一定会回到 $1$ 手中,假设传了 $x$ 次,球重新回到 $1$ 手中;

  并假设这 $x$ 次传球,共传了 $y$ 轮,如下图所示:

  

第 i 轮对应的序列 $(i-1)\cdot n+1,(i-1)\cdot n+2,\cdots ,i\cdot n$ 对应的 $people$ 编号为 $1,2,\cdots ,n$;

  也就是 $1+x\cdot k = 1+y\cdot n$,即 $x\cdot k = y\cdot n$;

  我们来分析一下这个等式可以推出什么神奇的东西:

  

  为什么要最小的 $x$ 呢?

  因为只要传球期间来到 $1$ 就停止,所以需要的是最小的 $x$;

 

  如果 $GCD(k,n) = k$,那么传一轮便可以来到 $1$ 处;

  如果 $GCD(k,n) \neq k$,那么需要传多轮才能来到 $1$ 处;

  那么下面来讨论 $GCD(k,n) \neq k$  的情况;

  假设 $GCD(k,n) = f$,这种情况下共传球 $x=\frac{n}{f}$ 次,与 $k=f$ 的传球次数相同;

  又因为 $f\ |\ k$,所以,这 $x$ 次传球的 $people$ 的编号一定相同;

  所以,对于任意 $k$,传球次数和编号只与 $GCD(n,k)$ 有关系;

  也就是只和 $n$ 的因子有关系;

 

  当 $GCD(n,k) = f$ 时,接到球的 $people$ 编号为:

    $1\rightarrow (1+f)\rightarrow (1+2f) \rightarrow \cdots \rightarrow (1+xf)$;

  共传球 $x=\frac{n}{f}$ 次;

  满足首项 $a_1=1$,末项 $a_{x+1}=n+1$,公差 $d=f$ 的等差数列;

  前 $x$ 项和即为当前的开心值;  

•Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 
 5 int n;
 6 vector<int >f;
 7 vector<ll >ans;
 8 
 9 void Factor(int n)///求解 n 的因子
10 {
11     f.clear();
12     for(int i=1;i*i <= n;++i)
13     {
14         if(n%i != 0)
15             continue;
16 
17         f.push_back(i);
18         if(n/i != i)
19             f.push_back(n/i);
20     }
21 }
22 void Solve()
23 {
24     Factor(n);
25 
26     for(int i=0;i < f.size();++i)
27     {
28         ll d=f[i];
29         ll x=n/f[i];
30         ll s=x*(1+1+(x-1)*d)/2;
31         ans.push_back(s);
32     }
33     sort(ans.begin(),ans.end());
34     for(int i=0;i < ans.size();++i)
35         printf("%lld ",ans[i]);
36 }
37 int main()
38 {
39     scanf("%d",&n);
40     Solve();
41 
42     return 0;
43 }
View Code

 


应用

•题目描述

•题解

  使得所有人都拿过球,类比于上题,也就是说求使得开心值为 $1+2+3+\cdots +n$ 的最大的 $k$;

  那么,只有当 $GCD(n,k)=1$ 时,球才会传递给 $x=n$ 个人;

  那么,本题就转化为求解 $GCD(n,k) = 1$ 的,并且满足 $k \le n$ 的最大的 $k$;

  显然,$k=n-1$ 为满足条件的最大的 $k$;

•变形

  如果限制 $k \le \frac{n}{2}$ 呢?

•分析

  如果 $n$ 为奇数,那么 $\lfloor{ \frac{n}{2} }\rfloor$ 一定与 $n$ 互素;

  如果 $n$ 为偶数,那么,如果 $\frac{n}{2}$ 为奇数,答案为 $\frac{n}{2}-2$;

  反之,如果 $\frac{n}{2}$ 为偶数,那么答案为 $\frac{n}{2}-1$,因为奇数与偶数一定互素;

  也就是说,直接判断 $\lfloor{ \frac{n}{2} }\rfloor\ ,\ \lfloor{ \frac{n}{2} }\rfloor-1\ ,\ \lfloor{ \frac{n}{2} }\rfloor-2$ 这三个数哪个与 $n$ 互素即可;

 

posted @ 2018-12-31 11:40  HHHyacinth  阅读(737)  评论(0编辑  收藏  举报