Little By Little( 二 )

本文精选了五道算法竞赛题目,包括逆向计算、数组排列、动态规划、快速幂及欧拉函数等算法,详细解析了每道题目的题意、算法思路与代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.小a的计算器

链接:https://ac.nowcoder.com/acm/contest/317#submit/%7B%22problemIdFilter%22%3A22142%2C%22statusTypeFilter%22%3A5%7D

题意:给你运算的过程和结果,让你逆推最开始的数

算法:简单模拟

思想:根据加减乘除四则运算反着算,如果是加变减,减变加,乘变除,除变乘。从后往前算。

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
long long b[105];
int a[105];
int main(){
    int n;
    long long x;
    cin>>n>>x;
    for(int i = 0; i < n; i++){
        cin>>a[i]>>b[i];
    }
    for(int i = n-1; i >= 0; i--){
        if(a[i] == 4)x *= b[i];
        else if(a[i] == 3)x /= b[i];
        else if(a[i] == 2) x += b[i];
        else x -= b[i];
    }
    cout<<x<<endl;
return 0;
}

2.小a与"204"

链接:https://ac.nowcoder.com/acm/contest/317/B

算法:简单模拟

题意:给你一个数组,数组里只包含2,4,0这三个数,问你怎么排列数组,使前一项减后一项的平方和最大。

思想:先统计2,4, 0的个数,当尽可能的4和0搭配时,前一项减后一项的平方和最大。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
#define maxn 1e5+5;
vector<int>v;
int main(){
    int n, a = 0, b = 0, c = 0, t;
    cin>>n;
    for(int i = 0; i < n;i++ ){//统计2,0,4的个数
        cin>>t;
        if(t == 0)a++;
        else if(t == 4)b++;
        else c++;
    }
    while(a && b){//尽可能的2和4进行搭配
        v.push_back(4);
        v.push_back(0);
        a--;
        b--;
    }
    if(a > 0){//当0有剩余的时候
        while(a && c){//0和2进行搭配
            v.push_back(2);
            v.push_back(0);
            a--;
            c--;
        }
        while(a > 0){//0有剩余
            v.push_back(0);
            a--;
        }
        while(c > 0){//2有剩余
            v.push_back(2);
            c--;
        }
    }
    if(b > 0){//4有剩余
       while(b && c){//4和2进行匹配
            v.push_back(4);
            v.push_back(2);

            b--;
            c--;
        }
        while(b ){//4有剩余
            v.push_back(4);
            b--;
        }
        while(c ){//2有剩余
            v.push_back(2);
            c--;
        }
    }
    if(!a && !b ){//0和4都没有剩余,只剩下2
        while(c){
            v.push_back(2);
            c--;
        }
    }
   // for(int i = 0; i < v.size(); i++){输出看看逻辑有没有问题
    //    cout<<v[i]<<" ";
   // }
    long long ans  = v[0]*v[0];
    int pre  = v[0];
    for(int i = 1; i < v.size(); i++){//进行运算
        ans += (v[i] - pre)*(v[i]-pre);
        pre = v[i];
       // cout<<ans<<endl;
    }
    cout<<ans<<endl;


}

3.小a与星际探索

链接:https://ac.nowcoder.com/acm/contest/317/C

算法:动态规划

题意:如果前面的数比后面的数大(不一定是连续的),那么此时的耐力值就跟候面的数异或一下,求最大的耐力值

思想:采用动态规划更新某点的最大耐力值

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 3005//本题采用动态规划,寻找到当前位置的最大值。
int a[maxn], vis[maxn], dp[maxn];
int main()
{
    int n;
    cin>>n;
    for(int i = 1; i <= n; i++)cin>>a[i];
    memset(vis, 0, sizeof(vis));
    dp[1] = a[1];
    vis[1] = 1;
    for(int i = 2; i <= n; i++){
        for(int j  = 1; j < i; j++){
            if(vis[j] == 0)continue;//后面没有更新到的数
            if(a[j] <= a[i])continue;//前面的不比后面的大
            dp[i] = max(dp[i], dp[j]^a[i]);//更新值
            vis[i] = 1;
        }
    }
    if(vis[n]){
        cout<<dp[n]<<endl;
    }
    else cout<<-1<<endl;//无法更新到n
    return 0;
}

4.小a与黄金街道

链接:https://ac.nowcoder.com/acm/contest/317/D

算法:快速幂,同余模定理,欧拉函数

题意:
小a和小b来到了一条布满了黄金的街道上。它们想要带几块黄金回去,然而这里的城管担心他们拿走的太多,于是要求小a和小b通过做一个游戏来决定最后得到的黄金的数量。
游戏规则是这样的:
假设道路长度为nn米(左端点为00,右端点为nn),同时给出一个数kk(下面会提到kk的用法)
设小a初始时的黄金数量为AA,小b初始时的黄金数量为BB
小a从11出发走向n−1n−1,小b从n−1n−1出发走向11,两人的速度均为1m/s1m/s
假设某一时刻(必须为整数)小a的位置为xx,小b的位置为yy,若gcd(n,x)=1gcd(n,x)=1且gcd(n,y)=1gcd(n,y)=1,那么小a的黄金数量A会变为A∗k^x(kg),小b的黄金数量B会变为B∗k^y(kg)
当小a到达n−1n−1时游戏结束
小a想知道在游戏结束时A+BA+B的值
答案对109+7109+7取模

思想:通过题意gcd(n,x)=1可以看出来,需要欧拉函数,而且A*k^x*k^z = A * k^(x+z),所以只需要根据欧拉函数求出互质的数之和

 根据Euler(x)∗x/2,就能求出互质的数之和,然后根据快速幂求出最后的结果。

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
const long long mod  = 1e9+7;
#define LL long long
LL quick_pow(LL a, LL b){//快速幂 同余模定理
   LL base = a;
   LL ans = 1;
   while(b){
        if(b & 1)ans  = (ans * base) % mod;
        b >>= 1;
        base = (base * base) % mod;
   }
   return ans;
}
LL Euler(int n){//欧拉函数
   LL ans = n;
   for(int i = 2; i <= sqrt(n); i++){
      if(n % i == 0){
        ans = ans / i * (i - 1);
        while(n % i == 0)
            n /= i;
      }
   }
   if(n > 1){
       ans = ans / n *(n-1);
   }
   return ans;
return 0;
}
int main(){
    int n, k, a, b;
    cin>>n>>k>>a>>b;
    LL ans = Euler(n)* n / 2;
    LL key = quick_pow(k, ans);
    cout<<(key*(a+b)%mod)%mod<<endl;
return 0;}

5.小a的子序列

链接:https://ac.nowcoder.com/acm/contest/317/F

算法:动态规划

题意:小a有一个长度为nn的序列,但是他忘了这个序列的样子,他只记得序列中的数大小在[1,V]内
你可以任意选择一些位置,并给它们赋值来组成一段子序列,需要满足序列中的数严格递增
一段子序列的“萌值”定义为序列中除最大数外所有数的乘积,若只有1个数则为1
他想请你求出所有合法子序列的“萌值”的和
不同子序列的定义为:存在某个值不同 或 在原序列中的位置不同
输出答案对1e9+7取模

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[5005][5005];
const ll mod=1e9+7;
int n,v;
int main()
{
    scanf("%d%d",&n,&v);
    for(int i=1;i<=v;i++) dp[i][1]=1;
    for(int i=2;i<=n;i++)
    {
        ll sum=1;
        for(int j=1;j<=v;j++)
        {
            dp[j][i]=(dp[j][i-1]+sum)%mod;
            sum=(sum+dp[j][i-1]*(ll)j)%mod;
        }
    }
    ll ans=0;
    for(int i=1;i<=v;i++) ans+=dp[i][n];
    cout<<ans%mod<<endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值