• 中石油训练混合训练第七场


    题目描述
    在某个游戏中,你接受了一个任务。这个任务要求你消灭n只狼。这些狼排成一排,每只狼都有两个攻击力a和b。如果你消灭一只狼,需要的代价是这只狼的a攻击力加上它旁边的狼的b攻击力。每消灭一头狼,它两边的狼(如果有)会并在一起,仍然保持一排。
    你需要求出:消灭所有狼的最小代价。
    输入
    输入第一行为一个正整数n。
    输入第二行为n个非负整数,按顺序表示每只狼的a攻击力;第三行为n个非负整数,表示每只狼的b攻击力。
    输出
    输出一行一个整数,为最小的代价。
    样例输入 Copy

    3 
    3 5 7 
    8 2 0
    

    样例输出 Copy

    17
    

    提示
    对于100%的数据,满足1≤n≤400,每只狼的a攻击力和b攻击力均不超过100000。
    首先说杭电有这个题 传送门
    先附上一片博客:传送门
    题目大意:一排狼,消灭这头狼需要消耗代价为这只狼的a战斗力和这头狼身边的狼的b战斗力
    所以先将输入的数据进行预处理:

    for(int i=1;i<=n;i++)
    	dp[i][i]=a[i]+b[i-1]+b[i+1];///左右两边都加上
    

    当一只狼被消灭之后,原先相邻的狼会靠在一起(相邻)
    设消灭第 i 匹狼到第 j 匹狼的最小代价为dp [ i ][ j ],那么很显然答案就是dp [ 1 ][ n ]。
    过程中需要枚举 i 到 j 之间的区间长度以及 k 即可
    在这里插入图片描述
    刚开始因为是dp[i][j]所以最后都要加上区间两侧的狼的b攻击力
    然后下面进行枚举的时候,还要取最小值
    这里枚举得是i——j的部分有一个类似于桥梁的东西 dp[i][k-1] dp[k+1][j] 和ak

    ll temp=dp[i][k-1]+a[k]+b[i-1]+b[j+1]+dp[k+1][j];
    dp[i][j]=min(dp[i][j],temp);
    

    经过一波操作之后将最终结果dp[i][n]输出

    #include <bits/stdc++.h>
    using namespace std;
    #define wuyt main
    typedef long long ll;
    #define HEAP(...) priority_queue<__VA_ARGS__ >
    #define heap(...) priority_queue<__VA_ARGS__,vector<__VA_ARGS__ >,greater<__VA_ARGS__ > >
    template<class T> inline T min(T &x,const T &y){return x>y?y:x;}
    template<class T> inline T max(T &x,const T &y){return x<y?y:x;}
    ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();
    if(c == '-')Nig = -1,c = getchar();
    while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();
    return Nig*x;}
    #define read read()
    const ll inf = 1e15;
    const ll INF = 0x3f3f3f3f;
    const int maxn = 2e6 + 7;
    const int mod = 1e9 + 7;
    ll gcd(ll a,ll b)
    {
        ll t;
        while(b!=0)
        {
            t=a%b;
            a=b;
            b=t;
        }
        return a;
    }
    ll qPow(ll x, ll k)
    {
        ll res = 1;
        while(k) {
            if(k&1)
                res=(res*x);
            k>>=1;
            x=(x*x);
        }
        return res;
    }
    ll maxx=-1;
    ll minn=inf;
    ll num2[maxn];
    ll num[maxn];
    ll res,ans;
    int sum=0;
    map<string,ll> mp;
    vector<ll> vet;
    priority_queue <int ,vector<int> ,greater<int> > xiaogen;
    queue <ll> duilie;
    priority_queue <int ,vector<int> ,less<int> > que;
    ll a[500],b[500];
    ll dp[500][500];
    int main()
    {
        int n=read;
        for(int i=1;i<=n;i++) a[i]=read;
        for(int i=1;i<=n;i++) b[i]=read;
        memset(dp,0x3f3f3f3f,sizeof dp);
        for(int i=1;i<=n;i++) dp[i][i]=a[i]+b[i-1]+b[i+1];///左右两边都加上
        for(int i=n-1;i>=1;i--){
            for(int j=i+1;j<=n;j++){
                ll temp1=dp[i+1][j]+a[i]+b[i-1]+b[j+1];
                ll temp2=dp[i][j-1]+a[j]+b[i-1]+b[j+1];
                dp[i][j]=min(temp1,temp2);
                for(int k=i+1;k<j;k++)
                {
                    ll temp=dp[i][k-1]+a[k]+b[i-1]+b[j+1]+dp[k+1][j];
                    dp[i][j]=min(dp[i][j],temp);
                }
            }
        }
        cout<<dp[1][n]<<endl;
        return 0;
    }
    /**
    3
    3 5 7
    8 2 0
     
    17
     
    **/
     
    /**************************************************************
        Problem: 15408
        Language: C++
        Result: 正确
        Time:108 ms
        Memory:35252 kb
    ****************************************************************/
    

    好朋友

    题目描述
    众所周知,XZ&CHR是好朋友……
    这天,CHR打算考验一下XZ与自己的默契度,他想了n个正整数:a1~ an,为了不为难XZ,CHR只要求说出一个数,这个数是a1 ~ an中任何一个数的倍数即可。当然,这还是十分困难,XZ知道后,觉得这很难,就来问问你:如果他在1~m中随机说出一个数,通过考验的概率是多少?

    输入
    第一行输入一个正整数T,代表有T组数据。
    对于每一组数据,第一行输入n,m, 第二行输入a1~an,含义见题目描述。

    输出
    为防止有精度问题,对于每一组数据输出概率乘上m,即一个正整数代表答案。
    样例输入

    1
    2 10
    2 3
    

    样例输出

    7
    

    提示
    样例解释:2、4、6、8、10是2的倍数,其他数中3、9是3的倍数,共7个。
    【数据范围】
    对于30%的数据,m ≤ 1000。
    对于另外20%的数据,n = 1。
    对于另外20%的数据,n = 2。
    对于所有数据,n ≤ 10,1<ai ≤ m ≤ 109,T ≤ 10000。

    在鄙人的这个文章里面
    在这里插入图片描述
    利用相似的做法,来解决这个问题
    看了大佬的做法感觉真的很秀,当天晚上调了好长时间的问题竟然被巨巨如此之短的代码解决,感觉真是太秀了

    需要注意的是:需要求两个数的最小公倍数,就像是上面那道题目的3*5类似的情况,因为3和5都是质数,所以就直接求了乘积,但是在这到题目里面并不适用,因此求两个数的最小公倍数才是正确的解决方式,每次循环的时候,要改符号(根据容斥原理来解决)
    但是上面大佬的一手DFS确实秀到我了,很强

    #include <bits/stdc++.h>
    using namespace std;
    #define wuyt main
    typedef long long ll;
    ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();
    if(c == '-')Nig = -1,c = getchar();
    while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();
    return Nig*x;}
    #define read read()
    const ll inf = 1e15;
    const ll INF = 0x3f3f3f3f;
    const int maxn = 2e6 + 7;
    const int mod = 1e9 + 7;
    ll gcd(ll a,ll b)
    {
        ll t;
        while(b!=0)
        {
            t=a%b;
            a=b;
            b=t;
        }
        return a;
    }
    ll lcm(ll a,ll b){
        return a/gcd(a,b)*b;
    }
    void DFS(int now,int op,ll fenmu){
        if(now!=1) ans+=m/fenmu*(op);
        for(int i=now;i<=n;i++) DFS(i+1,-op,lcm(fenmu,num[i]));
    }
    int main()
    {
        int cnt=read;
        while(cnt--){
            n=read,m=read;
            for(int i=1;i<=n;i++) num[i]=read;
            ans=0;
            /// 第一次之后*-1,所以开始要是-1而不是1
            DFS(1,-1,1);
            cout<<ans<<endl;
        }
        return 0;
    }
    /**
    1
    2 10
    2 3
    **/
    
    
  • 相关阅读:
    批处理文件入门
    批处理入门学习地址
    react资料
    React 学习参考资料链接
    Spring boot + jdbc学习笔记
    iOS-升级Https证书报错
    Java-006-循环结构和控制语句详解(while, dowhile ,for ,switch)
    Java-005-运算符详解
    Java-004-变量类型和修饰符详解
    Java-001简介和基础语法[类方法、实例方法、public class 与 class 区别](第一个Java程序)
  • 原文地址:https://www.cnblogs.com/PushyTao/p/13144143.html
Copyright © 2020-2023  润新知