ACM训练日记—3月25日(13届景驰—埃森哲杯比赛(牛客)题目整理)

本文精选了几道算法竞赛题目并提供了详细的解决方案,包括最长回文子序列、计算回旋图标的个数、求等式的解数等问题,通过动态规划、数学推导等方法解决了这些问题。

 D题 psd面试

 题意:求最长回文子序列。

      一定注意回文子序列和回文子串不是一回事,另外除了题目要求忽略字母大小写以外不要删除字符。

其他没什么了,直接用老办法dp干就可以了。还有dfs做的话会超时。

代码:

int DP_LPS(string str)
{
    int n=str.size();
    int tmp;
    vector< vector<int> > dp(n,vector<int>(n,0));
    for(int 
                tmp=dp[j+1][j+i-1] + 2;
            }
            else
i=0;i<n;i++)
    {//(1)一个元素的最长子序列
        dp[i][i]=1;
    }
    //(2)对于每一个[j,j+i]子序列的lps
    for(int i=1;i<n;i++)
    {
        tmp=0;
        for(int j=0;j+i<n;j++)
        {
            if(str[j] == str[j+i])
            {//首尾相同
            {//首尾不同
                tmp=max(dp[j+1][j+i], dp[j][j+i-1]);
            }
            dp[j][j+i]=tmp;//得到[j,j+i]子序列的LPS
        }
    }
    return dp[0][n-1];
}
 
int main()
{
    string s,s2;
    while(cin>>s)
    {
        int le=s.size();
        s2="";//清空操作
        for(int i=0;i<le;i++)
        {
            if(s[i]>='A'&&s[i]<='Z')s2+=(s[i]+32);
            else s2+=s[i];
        }
        cout<<le-DP_LPS(s2)<<endl;
    }
 
    return 0;
}

E题:回旋星空

题意:计算回旋图标的个数,即选中三颗星星,分别作为回旋图标的起点,拐点和终点,假设现在有三个星星分别为i,j,k,如果d(a[i],a[j]) == d(a[j],a[k])则表示找到了一个回旋图标,其中d(x,y)表示这两个点的欧氏距离为了给它很大的希望(i,j,k)和(k,j,i)被认为是两个不同的回旋图标。

        这道题目所给的数据量只允许n^2,所以其实就是一点点小技巧而已。

先用枚举所有点i,计算出该点i到其他所有点的距离存入一个map<double,int>,其中map是记录i点打其他所有点距离为double的点个数int。那么经过该点的成功组合数为C(int,2)*2。

代码:

const int maxn=1024;
struct node
{
    int x,y;
}a[maxn];
double dis(node a,node b)
{
    return sqrt(double((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
}
map<double,int>q;
map<double,int>::iterator it;
int main()
{
    int t;
    scanf("%d",&t);
    for(int m=0;m<t;m++)
    {
        int c=0;
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
        }
        if(n<3) {cout<<"WA"<<endl;continue;}
        q.clear();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i==j) continue;
                q[dis(a[i],a[j])]++;
            }
            for(it=q.begin();it!=q.end();it++)
            {
                int zz=it->second;
                if(zz>=2) c=c+(zz-1)*zz/2;
            }
            q.clear();
        }
        if(c!=0)cout<<c*2<<endl;
        else cout<<"WA"<<endl;
    }
    return 0;
}

        F题:等式

题意:给定n,求1/x + 1/y = 1/n (x<=y)的解数。(x、y、n均为正整数)

这题就是推导一下,先通分,在移项,两边都加n^2,整合式子变成(x-n)(y-n)=n^2,问题自然转化成求n^2有多少个满足条件的因数,因为n=(p1^a1)...(pn^a1),所以n^2=(p1^(2a1))...(pn^(2an)),那么显然n^2有(2a1+1)...(2an+1)个因数,毕竟pi可以取0个,1个,,,ai个。最后得出因子数x在输出(x+1)/2就行了。。。这道题其实挺水的。

代码:

const int MAXN = 1000000;
bool flag[MAXN];
int primes[MAXN / 3], pi;
void prime()
{
    int i, j;
    pi = 0;
    memset(flag, false, sizeof(flag));
    for (i = 2; i < MAXN; i++)
    {
        if (!flag[i])
            primes[pi++] = i;
        for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)
        {
            flag[i * primes[j]] = true;
            if (i % primes[j] == 0) //这句保证每个非素数只被筛去一次
                break;
}
    }
}
ll p[10005],cnt;
void solve(ll n)
{
    cnt=0;
    for(int i=0;i<pi&&primes[i]<=n;i++)
    {
        if(n%primes[i]==0)
        {
            ll k=0;
            while(n%primes[i]==0)
            {
                n/=primes[i];
                k++;
            }
            p[++cnt]=k;
        }
    }
    if(n>1) p[++cnt]=1;
}
int main()
{
    int T;
    prime();
    scanf("%d",&T);
    while(T--)
    {
        ll n,ans=1;
        scanf("%lld",&n);
        solve(n);//分解一下因数,保存每个因子的次方数

        for(int i=1;i<=cnt;i++)
        {
            ans=ans*(2*p[i]+1);
        }
        cout<<(ans+1)/2<<endl;
    }
}

       J题:强迫症序列

题意:他十分希望数组的每一个元素都一样大,每次操作只给这个数组的其中n-1个元素加1。

貌似这道题我们做出来的方法和题解不太一样。

就是给出一个序列一次操作给n-1个+1,相当于给其中一个-1,那么最小值和其他所有数的差加起来就是操作次数,然后最小值加操作次数就是最终状态。

代码:

using namespace std;
const int maxn=110000;
int dp[maxn];
 
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        long long mi=11000;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&dp[i]);
            if(mi>dp[i])mi=dp[i];
        }
        long long sum=0;
        for(int i=1;i<=n;i++)
        {
            sum+=dp[i]-mi;
        }
        printf("%lld %lld\n",sum,sum+mi);
    }
    return 0;
}

       L题:用来作弊的药水

题意:给出a,x,b,y判断a^x是否等于b^y,这个提就是快速幂,取模只要大于1e9的一个素数就行

代码:

const ll mod=1e9+7;
long long pow_mod(long long a,long long b,long long m)
{
    long long ans = 1;
    while(b)
    {
        if(b&1)//判断此时b[i]的二进制位是否为1
        {
            ans = (ans*a)%m;//乘到结果上,这里a是a^(2^i)%m
            b--;//把该为变0
        }
        b/=2;
        a = a*a%m;
    }
    return ans;
}


int main()
{
    ll x,y,a,b;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld%lld",&x,&a,&y,&b);
        ll ans1,ans2;
        ans1=pow_mod(x,a,mod);
        ans2=pow_mod(y,b,mod);
        if(ans1==ans2) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
}

内容概要:本文提出了一种基于非合作博弈理论的居民负荷分层调度模型,并结合双层鲸鱼优化算法(Two-level Whale Optimization Algorithm)进行高效求解,模型与算法均通过Matlab代码实现。研究针对电力系统中居民侧用电负荷的复杂调度问题,引入非合作博弈机制刻画各用户之间的利益竞争关系,实现负荷的分层优化分配;同时设计双层优化架构,上层优化资源配置,下层模拟用户自主决策行为,提升了模型的实用性与合理性。通过智能优化算法求解多层级、非凸非线性的博弈模型,有效提高了调度方案的收敛性与全局寻优能力,适用于现代智能电网中的需求侧管理与能源优化场景。; 适合人群:具备电力系统基础理论知识和Matlab编程能力,从事智能电网、能源优化调度、需求侧管理、博弈论应用等方向的科研人员、高校研究生及工程技术人员。; 使用场景及目标:①应用于居民区电力负荷的分层优化调度系统设计与仿真分析;②为非合作博弈在多主体能源系统建模中的应用提供方法论支持;③利用双层鲸鱼算法解决具有嵌套结构的复杂双层优化问题,提升求解效率与调度方案的可行性。; 阅读建议:建议读者结合提供的Matlab代码深入理解模型构建逻辑与算法实现流程,重点关注博弈模型的效用函数设计、纳什均衡求解思路以及双层优化结构的迭代机制,宜配合实际用电数据开展复现实验以验证模型有效性与鲁棒性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值