2020牛客暑期多校训练营(第四场)B-F-H(签到,其他看情况补)

B----Basic Gcd Problem

2020牛客暑期多校训练营(第四场)B-F-H(签到,其他看情况补)_第1张图片
2020牛客暑期多校训练营(第四场)B-F-H(签到,其他看情况补)_第2张图片

题意:

给你一个n,c,要你求 f c ( n ) fc(n) fc(n).

思路:

根据题意,

  1. 可以知道最贪心的做法是,每次都只去掉一个最小的因子, i i i 为x里去掉最小因子的数。
  2. 每一次操作都贡献一次c。那么问题就转换成了n有多少个因子
  3. 而题目是1e6的数据,n的大小是1e6那么直接求因子数的复杂度是 n l o g n nlogn nlogn,肯定 T L E TLE TLE
  4. 优化方法就是预处理,先处理出每一个数的因子个数。

AC

#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e6+10;
int vis[maxn],p[maxn];
int cnt[maxn];
void init()
{
    for(int i=0; i<=maxn-10; i++)vis[i]=1;
    vis[0]=vis[1]=0;
    int tot=0;
    for(int i=2; i<=maxn-10; i++)
    {
        if(vis[i])
        {
            p[++tot]=i;cnt[i]=1;
           for(int j=i*2; j<=maxn-10; j+=i)
           {
               vis[j]=0;
               cnt[j]=cnt[j/i]+cnt[i];
           }
        }
    }
}
int main()
{
    int t;
    init();
    scanf("%d", &t);
    while(t--)
    {
        ll n,c;
        scanf("%lld%lld",&n,&c);
        ll ans=1;
        for(int i=1; i<=cnt[n]; i++)ans=ans*c%mod;
        printf("%lld\n",ans%mod);
    }
    return 0;
}

F----Finding the Order(筛法)

2020牛客暑期多校训练营(第四场)B-F-H(签到,其他看情况补)_第3张图片
2020牛客暑期多校训练营(第四场)B-F-H(签到,其他看情况补)_第4张图片

题意:

给你四条线段,题目已知是平行。
让你判断是
2020牛客暑期多校训练营(第四场)B-F-H(签到,其他看情况补)_第5张图片

思路:(图是盗的,牛客某位大佬)

对于三角形,两边之和大于第三边。 2020牛客暑期多校训练营(第四场)B-F-H(签到,其他看情况补)_第6张图片
就转换成了判断哪两条是对角线

AC

#include 
using namespace std;
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        if(a+d>b+c)cout<<"AB//DC"<<endl;
        else cout<<"AB//CD"<<endl;
    }
    return 0;
}

H-----Harder Gcd Problem

本题题解,借鉴自
alan yyds,不用我多说了
本题其实是筛法的一个应用。

2020牛客暑期多校训练营(第四场)B-F-H(签到,其他看情况补)_第7张图片
2020牛客暑期多校训练营(第四场)B-F-H(签到,其他看情况补)_第8张图片

题意:

给你一个排列,要你找到最多的对数pair(每一对的公因子都是大于1)

思路:

可以从 i < = n i<=n i<=n内最大的质数开始枚举。

  1. 假如 p > n / 2 p>n/2 p>n/2,那么对于这个质数就没有与他配对的2p或者3p(因为都大于n),那么范围就缩减成 n / 2 n/2 n/2.
  2. 2这个质数最后操作
  3. 对于每一个质数p可以把和2的倍数有关的先去除,具体看代码。之后就是和筛法差不多。(先把可以用的倍数筛出来,之后再两两配对)
  4. 假如一个质数p,最后配对结果还剩下一个p(那么从2的集合中抽一个出来2p和它p配对)
  5. 最后就是2的操作。

AC

#include 
#include 
#include 
#include 
#define mp make_pair
#define sz(x) (int)(x.size())
using namespace std;
typedef pair<int,int>pa;
const int maxn=4e5+10;
const int maxm=2e6+10;
//int a[maxm],b[maxm];
bool p[maxm],use[maxn];
int cnt=0,a[maxn];
void init()
{
    for(int i=2; i<=maxn-10; i++)
    {
        if(!p[i])
        {
            for(int j=i*2; j<=maxn-10; j+=i)p[j]=1;
        }
    }
}
int main()
{
    init();
   // cout << "Hello world!" << endl;
   int t;
   scanf("%d", &t);
   while(t--)
   {
       int n;
       scanf("%d", &n);
       memset(use,0,n);
      vector<pa>ans;
      int cnt=0;
       for(int i=n/2; i>2; i--)
       {
           cnt=0;
           if(!p[i])
           {
               int j;
               for(j=i; j<=n; j+=i*2)if(!use[j])a[++cnt]=j;//+=i*2可以去除掉2的倍数
               for(j=cnt; j>1; j-=2)ans.push_back(mp(a[j],a[j-1])),use[a[j]]=use[a[j-1]]=1;
               if(j==1)ans.push_back(mp(a[j],a[j]*2)),use[a[j]]=use[a[j]*2]=1;
           }
       }
       cnt=0;
       for(int i=2; i<=n; i+=2)if(!use[i])a[++cnt]=i;
       for(int i=cnt; i>1; i-=2)ans.push_back(mp(a[i],a[i-1]));
       printf("%d\n",sz(ans));
       for(int i=0; i<sz(ans); i++)printf("%d %d\n",ans[i].first,ans[i].second);
   }
    return 0;
}

你可能感兴趣的:(与牛客的爱情)