2020牛客暑期多校训练第四场部分

B、Basic Gcd Problem

此题wa了16次,恶心的我不行
可以发现当前f[x] 肯定是c的幂次,那么就看x最大时c的多少幂次了。再看x和i的gcd,也就相当于x的约数
在这里插入图片描述
从上面看出规律,x如果要是最大,会从它的约数里面挑出最大的y,那么这个y也想最大,所以他也会从它的约数里面挑出z

\[x = k * y = k * (p * z) \]

所以也就是最长的上升的,任意两个数都是倍数关系的序列例如1,2,4,8,32,但是发现,这个不需要可以的去求最长了,最长的个数时固定的,贪心来讲,当前x到下面一个y,y = k * x,那么这个k应该最小,最小应该是什么呢,质数,一个质因子,那么在这个上升子序列里面所有k[i] , 满足y[i] = k[i] * x[i] , 并且肯定每个k都是质因子,长度也就等于n的质因子个数(可以枚举几个数试试)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#pragma GCC optimize(3 , "Ofast" , "inline")
using namespace std ;
#define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
#define x first
#define y second
typedef long long ll ;
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
ll in()
{
  ll x = 0 , f = 1 ;
  char ch = getchar() ;
  while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
  while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
  return x * f ;
}
ll qmi(ll a , ll b){
  ll res = 1 ;
  while(b) {
    if(b & 1) res = res * a % mod ;
    a = a * a % mod ;
    b >>= 1 ;
  }
  return res ;
}
void work(){
  int n , c ;
    scanf("%d%d" , &n , &c) ;
  int ans = 0 ;
  for(int i = 2; i <= n / i ;i ++)
   while(n % i == 0) n /= i , ans ++ ;
  if(n > 1) ans ++ ;
  printf("%d\n" , qmi(c , ans) % mod) ;
  return ;
}
int main()
{
  int t = in() ;
  while(t --) work() ;
  return 0 ;
}
/*
*/

F、Finding the Order

在这里插入图片描述
高手:两个三角形符合两边之和大于第三边,那么两个组合起来就是两个内边加起来大于两个外边

#include<bits/stdc++.h>
using namespace std;
int t,ac,ad,bc,bd;
int main(){
    cin>>t;
    while(t--){
        cin>>ac>>ad>>bc>>bd;
        if(ac+bd<ad+bc)cout<<"AB//CD"<<endl;else cout<<"AB//DC"<<endl;
    }
    return 0;
}

H、Harder Gcd Problem

在这里插入图片描述
比赛的时候就看出来规律了,只是没敢写,从图里面发现每个质数的所有倍数都可以两两组成一对,尽管这个倍数也可能既是2的倍数也可能是5的倍数,那么每个就枚举一个质数,枚举它的倍数 , 两两组成。但是交上去wa掉了,仔细一想,这个做法是贪心的, 那么这个做法到底够不够贪心呢,既然贪了,就要一贪到底。比较两个质数a , b , 如果a < b,那么在n里面肯定是a的倍数比较多,b的倍数比较小,甚至一个没有,既然贪心了,就要把每个数尽量的都要用了,此时对于a来说,它的倍数比较多,也比较好配对,b就相反,所以先配对b,尽量把b的倍数都用了,所以以此类推,枚举质数的时候从大到小枚举

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#pragma GCC optimize(3 , "Ofast" , "inline")
using namespace std ;
#define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
#define x first
#define y second
typedef long long ll ;
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 2e5 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
ll in()
{
  ll x = 0 , f = 1 ;
  char ch = getchar() ;
  while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
  while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
  return x * f ;
}
int prime[N] , vis[N] , tot ;
void get()
{
  for(int i = 2; i < N ; i ++) {
    if(!vis[i]) prime[++ tot] = i ;
    for(int j = 1; j <= tot && i * prime[j] < N ;j ++ ) {
      vis[i * prime[j]] = 1;
      if(i % prime[j] == 0) break ;
    }
  }
}
int f[N] ;
void work(){
  int n = in() ;
  int ans = 0 ;
  for(int i = 1; i <= n ;i ++ ) f[i] = 0 ;
  int pos = lower_bound(prime + 1,  prime + tot + 1 , n) - prime ;
  if(prime[pos] > n) pos -- ;
  for(int i = pos; i >= 1; i -- ) {
    int res = prime[i] ;
    for(int j = n / prime[i] * prime[i] ;j > prime[i] ;j -= prime[i]) {
      if(f[j]) continue ;
      if(!res) res = j ;
      else {
        ans ++ ;
        f[j] = res ;
        f[res] = j ;
        res = 0 ;
      }
    }
  }
  printf("%d\n" , ans) ;
  for(int i = 0 ;i <= n ;i ++ )
   if(f[i] > i)
    printf("%d %d\n" , i , f[i]) ;
  return ;
}
int main()
{
  get() ;
  int t = in() ;
  while(t --) work() ;
  return 0 ;
}
/*
*/

待续

posted @ 2020-07-20 20:00  spnooyseed  阅读(112)  评论(0编辑  收藏  举报