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$ 的编号和。
求所有的开心值,并按升序排列。
•题解
弱弱的我只能通过打表找规律%%%%%%%那些一眼看出规律的大神们
$egin{aligned} k &= 1 ightarrow 1 \ k&= 2 ightarrow 1,3 \ k&= 3 ightarrow 1,6 \ k&= 4 ightarrow 1,4,10 \ k&= 5 ightarrow 1,15 \ k&= 6 ightarrow 1,5,9,21 \ k&= 7 ightarrow 1,28end{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
View Code1 #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 Code1 #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("**** k=%d ",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 ",res); 37 a[tot++]=res; 38 } 39 40 sort(a,a+tot); 41 int t=unique(a,a+tot)-a; 42 printf(" =========== i=%d ",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
•分割线2019.6.14
•感悟
因打表找规律而AC的题,不能当作正解,赛后补题,要花时间思考正解;
•想法
从编号为 $1$ 的 $people$ 开始传球,依次传给其顺时针方向的第 $k$ 个人;
可以肯定的是,球一定会回到 $1$ 手中,假设传了 $x$ 次,球重新回到 $1$ 手中;
并假设这 $x$ 次传球,共传了 $y$ 轮,如下图所示:
第 i 轮对应的序列 $(i-1)cdot n+1,(i-1)cdot n+2,cdots ,icdot n$ 对应的 $people$ 编号为 $1,2,cdots ,n$;
也就是 $1+xcdot k = 1+ycdot n$,即 $xcdot k = ycdot n$;
我们来分析一下这个等式可以推出什么神奇的东西:
为什么要最小的 $x$ 呢?
因为只要传球期间来到 $1$ 就停止,所以需要的是最小的 $x$;
如果 $GCD(k,n) = k$,那么传一轮便可以来到 $1$ 处;
如果 $GCD(k,n) eq k$,那么需要传多轮才能来到 $1$ 处;
那么下面来讨论 $GCD(k,n) eq 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 ightarrow (1+f) ightarrow (1+2f) ightarrow cdots ightarrow (1+xf)$;
共传球 $x=frac{n}{f}$ 次;
满足首项 $a_1=1$,末项 $a_{x+1}=n+1$,公差 $d=f$ 的等差数列;
前 $x$ 项和即为当前的开心值;
•Code
View Code1 #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 }
应用
•题目描述
•题解
使得所有人都拿过球,类比于上题,也就是说求使得开心值为 $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} } floor$ 一定与 $n$ 互素;
如果 $n$ 为偶数,那么,如果 $frac{n}{2}$ 为奇数,答案为 $frac{n}{2}-2$;
反之,如果 $frac{n}{2}$ 为偶数,那么答案为 $frac{n}{2}-1$,因为奇数与偶数一定互素;
也就是说,直接判断 $lfloor{ frac{n}{2} } floor , lfloor{ frac{n}{2} } floor-1 , lfloor{ frac{n}{2} } floor-2$ 这三个数哪个与 $n$ 互素即可;