zoukankan      html  css  js  c++  java
  • 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$ 的编号和。

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

    题解

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

      $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

     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("****
    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
    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 ,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

     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} } 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$ 互素即可;

  • 相关阅读:
    LAMP搭建示例
    MySQL主从
    list多字段去重
    mysql按照某一个条件进行分组统计,同时又要保证一个相同字段的数据只统计一次
    sentinel自定义异常处理
    sentinel规则持久化
    zookeeper
    shiro
    iframe之间传递参数
    自定义标签
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10201691.html
Copyright © 2011-2022 走看看