H,E题

H题方法一:贪心求上升子序列的最少个数

#include<bits/stdc++.h>
using namespace std;

int n,m,cnt,a[5005],f[5005];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    
    vector<int> b;
    for(int i=1;i<=n;i++)//贪心求上升子序列的最少个数
    {
        int idx=0,gap=0x3f3f3f3f;
        for(int j=0;j<b.size();j++)
            if(b[j]<=a[i] && a[i]-b[j]<gap)gap=a[i]-b[j],idx=j;

        if(gap==0x3f3f3f3f)b.push_back(a[i]);
        else b[idx]=a[i];
    }
    cnt=b.size();
    
    if(cnt>m)cout<<"Karashi lovelove"<<endl;//非法
    else cout<<"Karashi cblcd"<<endl;//合法
    
    return 0;
}

贪心做法因为vector b数组是有序的,所以内层循环可以用二分优化为nlogn,可以试一试,数据比较小不优化n^2也能过

H题方法二:动态规划,根据Dilworth定理转换为最长不升子序列的长度问题

#include<bits/stdc++.h>
using namespace std;

int n,m,cnt,a[5005],f[5005];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
        
    //根据Dilworth定理:上升子序列的最少个数==最长不升子序列的长度
    for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<i;j++)
            if(a[i]<=a[j])f[i]=max(f[i],f[j]+1);
        cnt=max(cnt,f[i]);
    }
    
    if(cnt>m)cout<<"Karashi lovelove"<<endl;//非法
    else cout<<"Karashi cblcd"<<endl;//合法
    
    return 0;
}

E题:数论

暴力是n^2,会超时,想办法处理原等式,需要对算术基本定理有一定的了解

Ai^2==k×Aj, 根据算术基本定理,想要Aj变为平方数,即将Aj 中奇数次幂的质因子变为偶数次幂,所以k就为Aj的每种质因数的偶次幂组合出来的。 所以我们可以先求出最小的k为X,其他的k是在X的基础上乘以其他Aj的质因数偶次幂而来的,所以一定有sqrt(k)%sqrt()==0,故sqrt(X×Aj)一定是Ai=sqrt(k×Aj)的约数,所以倒序枚举先将后面所有的sqrt(X×Aj)存入桶中统计个数,枚举Ai的约数,然后累加其约数之前出现的次数即可

#include<bits/stdc++.h>
#define int long long
using namespace std;

int n,res,a[100005];

int f(int x)//返回(X×Aj)
{
    int ans=x;
    for(int i=2;i<=x/i;i++)//分解质因数
    {
        if(x%i==0)
        {
            int cnt=0;
            while(x%i==0)
            {
                cnt++;
                x/=i;
            }
            if(cnt&1)ans*=i;
        }
    }
    if(x>1)ans*=x;
    return ans;
}

signed main()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    
    map<int,int> h;//用于桶计数
    for(int i=n;i>=1;i--)
    {
        int t=a[i];
        for(int j=1;j<=t/j;j++)//枚举a[i]的约数
        {
            if(t%j==0)
            {
                res+=h[j];
                if(t/j!=j)res+=h[t/j];//注意约数是否成对存在
            }
        }
        
        int k=f(t);
        h[sqrt(k)]++;
    }
    
    cout<<res<<endl;
    return 0;
}