同济校赛(5.21场)

同济校赛(牛客5.21)

A.盒饭盲盒

  • 题解

​ 排列组合的定义题,分别计算全荤的事件数量以及总事件数量,注意全素是不会发生的需要剔除,计算下面式子代表的概率后,gcd计算最简分数形式
p = ( m − a ) 3 m 3 − a 3 = ( m − a ) 2 m 2 + m a + a 2 p=\frac{(m-a)^3}{m^3-a^3}=\frac{(m-a)^2}{m^2+ma+a^2} p=m3a3(ma)3=m2+ma+a2(ma)2

  • 代码
#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
typedef long long LL;

LL gcd(LL a, LL b)  // 欧几里得算法
{
    return b ? gcd(b, a % b) : a;
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        LL m,a,b,c;
        scanf("%lld%lld", &m, &a);
        b=m-a;b*=b;
        c=m*a;
        m*=m;
        a*=a;
        
        LL d=gcd(b,m+a+c);
        printf("%lld/%lld\n",b/d,(m+a+c)/d);
    }
    return 0;
}

K.乐观的R家族

  • 题解

​ 同一题某答案选的人越多总分和越大,故只需统计每题选的人最多答案乘分值最后相加

  • 代码
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 1010;
int n,m;
char s[N][N];
int a[N];

int main()
{
    cin>>n>>m;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < m; j ++ )
            cin>>s[i][j];
    
    for (int i = 0; i < m; i ++ )cin>>a[i];
    
    long long res=0;//防爆int
    for (int i = 0; i < m; i ++ ){//遍历每列,即看每一题的情况
        int cnt[5]={0};//哈希计数
        int m=-1;
        for (int j = 0; j < n; j ++ ){//统计每个答案的数量
            cnt[s[j][i]-65]++;
        }
        for (int j = 0; j < 5; j ++ ){//找选择最多的
            m=max(m,cnt[j]);
        }
        res+=m*a[i];//当前题最大分总和
    }
        
    cout << res<<'\n';
    return 0;
}

C. 攻城

  • 题解

    题目可以转化为每6次单点攻击后进行一次群体攻击,且(n!=1/0)最后一次群体攻击时的血量分布全为1。因此可以推出两个必要条件:

    1.血量和 sum % (6+n) == 0;

    2.最小血量塔 min>=(sum/(6+n)),即最小血量塔要能承受应有的群体攻击

  • 代码

#include <iostream>
#include <cstdio>

using namespace std;
typedef long long LL;

int main()
{
    int t;
    scanf("%d", &t);
    while (t -- ){
        int n,x,mi=0x3f3f3f3f;
        scanf("%d", &n);
        
        LL sum=0;
        for (int i = 0; i < n; i ++ ){
            scanf("%d", &x);
            sum+=x;
            mi=min(mi,x);
        }
        if(n==0 || n==1){printf("YES\n");continue;}//特判0,1
        
        int flag=0;
        if(sum%(6+n)==0 && mi>=(sum/(6+n)))flag=1;
        if(flag)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

D.两串糖果

  • 题解

    其实一眼区间dp,dp[i]表示0~i中通过各种交换后的最大值,v[i] [j]为不变换的区间乘积和,rev[i] [j]为区间反转后的区间乘积和。状态转移方程:
    d p [ i ] = m a x ( d p [ i ] , d p [ j ] + m a x ( v [ j + 1 ] [ i ] , r e v [ j + 1 ] [ i ] ) ) dp[i]=max(dp[i],dp[j]+max(v[j+1][i],rev[j+1][i])) dp[i]=max(dp[i],dp[j]+max(v[j+1][i],rev[j+1][i]))

v [ i ] [ j ] = v [ i + 1 ] [ j − 1 ] + a [ i ] ∗ b [ i ] + a [ j ] ∗ b [ j ] v[i][j]=v[i+1][j-1]+a[i]*b[i]+a[j]*b[j] v[i][j]=v[i+1][j1]+a[i]b[i]+a[j]b[j]

r e v [ i ] [ j ] = r e v [ i + 1 ] [ j − 1 ] + a [ i ] ∗ b [ j ] + a [ j ] ∗ b [ i ] rev[i][j]=rev[i+1][j-1]+a[i]*b[j]+a[j]*b[i] rev[i][j]=rev[i+1][j1]+a[i]b[j]+a[j]b[i]

解题过程:

  1. 预处理v[n] [n]和rev[n] [n],从上述v,rev的转移方程知必须先把长度为1和2的区间最先预处理出来
  2. 区间dp,注意第二重循环从0开始
  • 代码
#include <iostream>

using namespace std;
typedef long long LL;
const int N = 5005;

int n,a[N],b[N];
LL v[N][N],rev[N][N],f[N];

int main()
{
    cin>>n;
    for (int i = 1; i <= n; i ++ )cin>>a[i];
    for (int i = 1; i <= n; i ++ )cin>>b[i];
    
    for (int i = 1; i <= n; i ++ ){v[i][i]=a[i]*b[i];rev[i][i]=v[i][i];}//长度为1预处理
    for (int i = 1; i < n; i ++ )//长度为2的预处理
    {
      v[i][i+1]=v[i][i]+v[i+1][i+1];
      rev[i][i+1]=a[i]*b[i+1]+a[i+1]*b[i];
    }
    for (int j = 1; j <= n; j ++ )//预处理v,rev
        for (int i = 1; i < j-1; i ++ ){
            v[i][j]=v[i+1][j-1]+a[i]*b[i]+a[j]*b[j];
            rev[i][j]=rev[i+1][j-1]+a[i]*b[j]+a[j]*b[i];
        }
        
    for (int i = 1; i <= n; i ++ )//区间dp
        for (int j = 0; j < i; j ++ )
            f[i]=max(f[i],f[j]+max(v[j+1][i],rev[j+1][i]));
            
    cout<<f[n]<<'\n';

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值