cf #802 Div.2

cf #802 Div.2

A. Optimal Path

  • 题意

​ 给定一个n*m的棋盘,棋盘下标从1开始,每个格子(i,j)的值为(i-1)m+j,且只能无回头的从(1,1)到(n,m),求所经过路径的所有格子的值之和最小为多少

  • 题解

    贪心,无证明,当沿着第一行走到头后再沿着最后一列走到终点的路径和最小

  • 代码

#include <iostream>

using namespace std;

int main() {
    int T;
    cin>>T;
    while(T--) {
        long long n,m;//注意爆int
        cin>>n>>m;
        cout<<m*(m+n+n*n-1)/2<<'\n';//考察等差数列的前n项和
    }
    
    return 0;
}

B. Palindromic Numbers

  • 题意

    给定数的长度n,以及一个长度为n的数a,求一个长度相同的数b使得a+b是一个回文数字

  • 题解

    假定n=4

    那么对于任意一个a=9xxx,一个四位数b一定会使得a+b为5位数,所以可以指定a+b=11111,那么b可以由11111-a得到

    对于任意一个a=Yxxx(Y<9),一个四位数b一定可以使得a+b=9999,所以可以指定a+b=9999,那么b可以由9999=a得到

    因此,对于任意的n也是如此,但是注意n很大,所以需要高精度计算;或者转为字符串来做

  • 代码

#include <iostream>
#include <vector>

using namespace std;

vector<int> sub(vector<int> A,vector<int> B)
{
    vector<int> c;
    int t=0;
    for(int i=0;i<A.size();i++)
    {
        t=A[i]-t;
        if(i<B.size())t-=B[i];
        c.push_back((t+10)%10);
        t=(t<0);
    }
    
    while(c.size()>1&&c.back()==0)c.pop_back();
    
    return c;
}

int main() {
    int t;
    cin>>t;
    while(t--) {
        int len;cin>>len;
        string s;cin>>s;
        
        vector<int> a,b;
        for(int i=s.size()-1;i>=0;i--) a.push_back(s[i]-'0');
        
        if(s[0]!='9')
            for(int i=0;i<s.size();i++) b.push_back(9);
        else 
            for(int i=0;i<=s.size();i++) b.push_back(1);
            
        auto c=sub(b,a);
        for(int i=c.size()-1;i>=0;i--) cout<<c[i];
        cout<<'\n';
    }
    
    return 0;
}

C. Helping the Nature

  • 题意

    对于一个数组a,经过以下三种操作使得所有值都变成0的最小操作数
    1. a [ 1... i ] − 1 2. a [ i . . . n ] − 1 3. a [ 1... n ] + 1 \begin{align} &1. a[1...i]-1 \\ &2. a[i...n]-1 \\ &3. a[1...n]+1 \end{align} 1.a[1...i]12.a[i...n]13.a[1...n]+1

  • 题解

    对区间操作可以利用差分转变成对单点操作,数组a的差分数组d,操作变成
    1. d [ 1 ] − 1 , d [ i + 1 ] + 1 2. d [ i ] − 1 3. d [ 1 ] + 1 \begin{align} &1.d[1]-1,d[i+1]+1\\ &2.d[i]-1\\ &3.d[1]+1 \end{align} 1.d[1]1,d[i+1]+12.d[i]13.d[1]+1
    要使得a数组全为0,转换成求d全变为0的最小操作数。

    当d[i]>=0,使用操作2即可

    当d[i]<0,可以用操作1把d[i]变为0;但同时也把d[1]变动了,但是没关系,1这个位置既可以用操作3加,也可以用操作2减。

    那么把1位置除外,把2~n处理完,1字形单独处理

  • 代码

#include <iostream>
#include <cmath>

using namespace std;
const int N=2e5+5;

long long t,n,a[N],d[N];//素以爆int

int main() {
    cin>>t;
    while(t--) {
       cin>>n;
       for(int i=1;i<=n;i++) cin>>a[i];
       for(int i=1;i<=n;i++) d[i]=a[i]-a[i-1];
       
       long long res=0;
       for(int i=n;i>1;i--)
            if(d[i]>=0) res+=d[i];
            else {
                res-=d[i];
                d[1]+=d[i];
            }
        
        cout<<res+abs(d[1])<<'\n';
    }
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值