目录
A.Orac and Fac
1:问题描述
给定一组数,每组数有n和k两个数,问k次n=n+f(n)之后n的值,其中f(n)让求的是n的最小正除数。
2:问题分析:
这道题分为两个部分,奇数部分和偶数部分,观察发现f(偶数)=2,f(奇数)不确定是多少,那么我们只需要判断n是否是奇数,并从2到sqrt(n)能否被n整除就行了,若能则f(n)=n,反之f(n)=当前这个值;如果n为偶数的时候,n只需要加上k个2就行了。
3:代码:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mem(a,b) memset(a,b,sizeof(a))
#define fr(x,n) for(int i=x;i<=n;++i)
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pll pair<ll,ll>;
const double PI=acos(-1.0);
const double eps=1e-9;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=2e5+100;
const int maxm=4e4;
const ll mod=1000000007;
inline int read()
{
char ch = getchar();
int x = 0, f = 1;
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
ll solve(int n){
ll m=sqrt(n),indexx=1;
for(int i=2;i<=m;++i){
if(n%i==0){
indexx=i;
break;
}
}
if(indexx==1) indexx=n;
return indexx;
}
ll n,k;
int main()
{
int T=read();
for(;T;T--){
scanf("%lld%lld",&n,&k);
if(n%2==1){
n+=solve(n);
k--;
}
if(n%2==0){
n+=2*k;
}
printf("%lld\n",n);
}
return 0;
}
B.Orac and Models
1:问题描述
给定一个长度为n的序列,序列的下标从1到n,让我们找到一个最长的子序列,使得这个子序列满足相邻两个数右边的数比左边的数大并且右边的数的下标能整除左边那个数的下标。
2:问题分析:
1:dp
数据范围是1e5,那么可以在O(nsqrt(n))内找到每一个数的约数,找到约数之后就可以通过dp找到最长的序列。
2:dfs
枚举1-n里面的每个数,对于这个数从2(倍数)开始往后面dfs.
3:代码
1:dp
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mem(a,b) memset(a,b,sizeof(a))
#define fr(x,n) for(int i=x;i<=n;++i)
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pll pair<ll,ll>;
const double PI=acos(-1.0);
const double eps=1e-9;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+1;
const int maxm=4e4;
const ll mod=1000000007;
inline int read()
{
char ch = getchar();
int x = 0, f = 1;
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
int num[maxn][500];
void init(int nn){
for(int i=2;i<=nn;++i){
int number=sqrt(i);
for(int j=1;j<=number;++j){
if(i%j==0){
num[i][ ++num[i][0] ]=j;
if(i/j!=j) num[i][ ++num[i][0] ]=i/j;
}
}
sort(num[i]+1,num[i]+num[i][0]+1);
}
}
int a[maxn],dp[maxn];
int main()
{
init(maxn);
int T=read();
for(;T;T--){
int n=read();
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
dp[i]=1;
}
dp[0]=0;
int num_puts=1;
for(int i=2;i<=n;++i){
for(int j=1;j<=num[i][0];++j){
if( a[i]>a[ num[i][j] ] ){
dp[i]=max( dp[i],dp[ num[i][j] ]+1 );
// cout<<dp[i]<<endl;
}
}
num_puts=max(num_puts,dp[i]);
}
cout<<num_puts<<endl;
}
return 0;
}
2:dfs
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mem(a,b) memset(a,b,sizeof(a))
#define fr(x,n) for(int i=x;i<=n;++i)
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pll pair<ll,ll>;
const double PI=acos(-1.0);
const double eps=1e-9;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+1;
const int maxm=4e4;
const ll mod=1000000007;
inline int read()
{
char ch = getchar();
int x = 0, f = 1;
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
ll n,num_puts;
ll a[maxn];
void dfs(ll number,ll indexx){
num_puts=max(num_puts,indexx);
for(ll i=2;i<=n;++i){
if(i*number>n){
num_puts=(indexx,num_puts);
return ;
}
else{
if( a[ number*i ]>a[ number ] ){
dfs(number*i,indexx+1);
}
}
}
}
int main()
{
int T=read();
for(;T;T--){
n=read();
num_puts=1;
for(ll i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
for(ll i=1;i<=n;++i){
dfs( i,1 );
}
cout<<num_puts<<endl;
}
return 0;
}
C.Orac and LCM
1:问题描述
给定n个数,让求gcd({lcm({ai,aj})|i<j}).
2:问题分析:
n个数,有n*(n-1)/2种组合方式,让我们求所有数的gcd.
首先说一下唯一分解定理:一个数n肯定能被分解成 n=p1^a1 * p2^a2 . . .*pn^an
对于两个数来说:
n=p1^a1 * p2^a2 . . .*pn^an
m=p1^b1*......*pn^bn.
gcd(n,m)=p1^min(a1,b1)*....*pn^min(an,bn).
lcm(n,m)=p1^max(a1,b1)*....*pn^max(an,bn).
那么分析一下,如果说对于两个数n和m,它们都没有2这个因子的话,其实就是说他们的最小公倍数里面没有2这个因子,那么最后的gcd也一定不存在2.
那么只有当某一个因子的个数大于等于n-1的时候这个因子才会存在.
1:如果因子个数为n-1
那么切入点应该是没有当前因子的那个数,分析lcm是两个数中最大的那一个.
即便是这样,当2^0与2^2(因子2个数最小的那一个)结合后仍然会变成2^2,最后求gcd的时候结果仍然是2^2,也就是最小的那个一个。
2:如果因子个数为n
那么会存在因子个数最小的和因子个数次小的那个进行比较,这个时候最后应该是次小的那一个。
3:代码
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mem(a,b) memset(a,b,sizeof(a))
#define fr(x,n) for(int i=x;i<=n;++i)
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pll pair<ll,ll>;
const double PI=acos(-1.0);
const double eps=1e-9;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=2e5+100;
const int maxm=4e4;
const ll mod=1000000007;
int head[maxn],tot;
inline int read()
{
char ch = getchar();
int x = 0, f = 1;
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
ll a[maxn];
vector<int>v[maxn];
int n;
bool number[maxn+5];
int prime[maxn+5],p[maxn],numb[maxn];
void solve(ll x)
{
for(ll i=2;i<=sqrt(x);i++)
{
if(x%i==0){
p[++tot]=i;
numb[tot]=0;
while(x%i== 0) {
x/= i;
numb[tot]++;
}
}
}
if(x>1){
p[++tot]=x;
numb[tot] = 1;
}
for(int i=1;i<=tot;i++){
v[p[i]].push_back(numb[i]);
}
}
ll solveee(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a;
a=a*a;
b>>= 1;
}
return ans ;
}
int main()
{
int n=read();
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;++i){
tot=0;
solve(a[i]);
}
for(int i=0;i<200000;++i){
sort( v[i].begin(),v[i].end() );
}
ll putsss = 1;
for(int i = 1;i<=200000;i++){
if(v[i].size()== 0)continue;
if(v[i].size()>=n-1){
if(v[i].size()== n){
putsss=putsss*solveee(i,v[i][1]);
}
else putsss=putsss*solveee(i,v[i][0]);
}
}
cout << putsss << endl;
return 0;
}
D.Orac and Medians
1:问题描述
给定一个长为n的数组,又给了一个k,现在问我们是否能通过一些操作把这个数组里面的数都变成k.
操作为:选定一个从l到r的区间,计算区间中位数(下取整)xx,然后把这个区间上面的所有的值变成区间第xx小。
2:问题分析:
1:通过问题分析我们能够看到,如果要使得整个区间变成k,那么这个数组里面就必须含有k.
2:如果存在相邻两个数大于等于k或者三个数的两端的两个数大于等于k的话,就能够使得区间里面的所有数变为k.
3:通过2的操作,我们能够使得区间的值之后k和大于k的两种.
4:那么就一定可以使得整个数组变为k.
3:代码
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mem(a,b) memset(a,b,sizeof(a))
#define fr(x,n) for(int i=x;i<=n;++i)
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pll pair<ll,ll>;
const double PI=acos(-1.0);
const double eps=1e-9;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=2e5+100;
const int maxm=4e4;
const ll mod=1000000007;
int n,k;
int a[maxn];
bool solve(){
for(int i=1;i<=n;++i){
if(a[i]>=k){
if(i!=1){
if(a[i]<=a[i-1]) return true;
}
if(i!=n){
if(a[i]<=a[i+1]) return true;
}
}
if(i+2<=n){
if(a[i]>=k&&a[i+2]>=k){
return true;
}
}
}
return false;
}
int main()
{
int T;
cin>>T;
while(T--){
bool flag1=false;
bool flag2=false;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
if(a[i]==k){
flag1=true;
}
}
if(!flag1){
cout<<"no\n";
continue;
}
if(n==1&&flag1){
cout<<"yes\n";
continue;
}
if(solve()) flag1=true;
else flag1=false;
if(flag1) cout<<"yes\n";
else cout<<"no\n";
}
return 0;
}