首页 > 其他分享 >2022.10.17-D 摩斯电码

2022.10.17-D 摩斯电码

时间:2022-10-18 11:22:54浏览次数:66  
标签:cnt frac 17 int max rd return 2022.10 摩斯电码

感谢 lby奆奆 的指导。

思路:

首先,\(1\) 号的票肯定是越多越好,因此 \(a_1,a_n\) 一定都是投给 \(1\) 号。

我们考虑二分 \(1\) 号能获得的席位数 \(x\)。

显然,对于所有 \(\frac{v_i}{s}>\frac{v_1}{x}\),它们都会占有一个席位(这里的 \(v_i\) 表示 \(i\) 最后的得票数)。

那问题就转化为求 \(>\frac{v_1}{x}\) 的最小个数,并判断最小个数是否 \(\le m-x\)。

我们考虑设计状态:\(f_{i,j}\) 表示 \(i\) 号从 \(a_i\) 获得了 \(j\) 票(注意只是 \(a_i\),而不是总票数)。

因此有转移:

\[f_{i,j+(a_{i-1}-k)}=\min\{f_{i-1,k}+\lfloor\frac{x(j+a_{i-1}-k)}{v_1}\rfloor\} \]

这里的 \(a_{i-1}-k\) 就是前一个群众剩下的票。

但这样的时间复杂度是 \(nt^2\log m\) 的(\(t\) 表示值域)。

那我们能不能将票数席位交换一下呢?

考虑重新设计状态:\(f_{i,j}\) 表示 \(s\sim i\) 一共取得 \(j\) 个席位,\(i\) 号需要在 \(a_i\) 最多拿多少票。

现在的判断就变成:是否存在某个 \(f_{n,j}\) 被转移到。

为什么是正确的呢?感性理解一下,我在保证 \(i\) 号最多只能取 \(j\) 个席位的情况下,那么我在 \(a_i\) 多拿一些,\(i+1\) 号在 \(a_i\) 就少拿一些,那么 \(i+1\) 能拿到的席位就变少了。

考虑这时候的转移:设 \(cnt\) 为满足 \(\frac{v_i}{j+1}\le\frac{v_1}{x}<\frac{v_i}{j}\) 的最大 \(v_i\)

因此有 \(cnt=\lfloor\frac{v_1(j+1)}{x}\rfloor\),且 \(cnt\times x>v_1\times j\) 时在有转移:

\[f_{i, j+k}=\max\{cnt - (a_{i - 1} - f_{i-1,k}) - v_i\} \]

时间复杂度为 \(O(nm\log m)\)


代码

#include<bits/stdc++.h>
#define LL long long
#define max(x...) std::max({x})
#define min(x...) std::min({x})
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
inline int rd()
{
    int sign = 1, re = 0; char c = getchar();
    while(!isdigit(c)){if(c == '-') sign = -1; c = getchar();}
    while(isdigit(c)){re = re * 10 + (c - '0'); c = getchar();}
    return sign * re;
}
int n, m, v[55], a[55];
LL f[55][505];
inline bool chk(int x)
{
    memset(f, -1, sizeof(f));
    FOR(i, 0, m - x)
    {
        LL L = 1ll * v[1] * i, R = 1ll * v[1] * (i + 1), cnt = R / x;
        if(!i) L = -1;
        if(cnt * x > L)
            f[2][i] = max(f[2][i], cnt - v[2]);
    }
    FOR(s, 3, n) FOR(i, 0, m - x) if(~f[s - 1][i])
    {
        int pre = max(0ll, a[s - 1] - f[s - 1][i]);
        FOR(j, 0, m - x - i)
        {
            LL L = 1ll * v[1] * j, R = 1ll * v[1] * (j + 1), cnt = R / x;
            if(!j) L = -1;
            if(cnt * x > L)
                f[s][i + j] = max(f[s][i + j], cnt - pre - v[s]);
        }
    }
    FOR(i, 0, m - x) if(~f[n][i]) return 1;
    return 0;
}
signed main()
{
    n = rd(), m = rd();
    FOR(i, 1, n) v[i] = rd();
    FOR(i, 1, n) a[i] = rd();
    v[1] += a[1] + a[n];
    int l = 0, r = m + 1;
    while(l + 1 < r)
    {
        int mid = (l + r) >> 1;
        if(chk(mid)) l = mid;
        else r = mid;
    }
    printf("%d", l);
    return 0;
}

标签:cnt,frac,17,int,max,rd,return,2022.10,摩斯电码
From: https://www.cnblogs.com/zuytong/p/16801981.html

相关文章

  • 2022-10-17 上涨过程中的下跌区分,纳斯达克最近的2次下跌记录
     先看第一段下跌1.是日线的下跌一段,然后一个阳线的单K线反转。注意,这里虽然是单根K线很强,但是整体还处于下降段。所以之后的调整还是很重要的2.30分钟还是处于一个中......
  • 【2022.10.18】Linux入门基础(1)
    内容概要主题:linux运维(记)linux基础几乎以记忆为主(理论知识)运维的本质服务器介绍服务器品牌服务器参数服务器组件磁盘阵列虚拟化技术虚拟化软件安装虚......
  • [2022.10.18]构造器
    类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:1.必须和类的名字相同2.必须没有返回类型,也不能写void构造器:1.和类名相同2.......
  • 10.17
    T1线段树优化DP[COCI2015-2016#1]RELATIVNOST题目描述您是一位计数大师,有一天您的朋友Luka出了一道问题来刁难您。Luka是一位勤劳的画家,他的画很好,所以会有\(n\)......
  • 2022-10-17学习内容
    1.向下一个Activity发送数据1.1activity_act_send.xml<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/and......
  • 10.17
    #include<stdio.h>intmain(){ unsignedlonglongn,i,m=1; scanf("%llu",&n); for(i=1;;i++) {if(n/10==0) {break; }else{ n=n/10; m++;} } printf("%llu",m......
  • 【LeetCode】1732. 找到最高海拔(C++)
    1732.找到最高海拔(C++)​​1题目描述​​​​2示例描述​​​​2.1示例1​​​​2.2示例2​​​​3解题提示​​​​4源码详解(C++)​​1题目描述有一个自行车手打算......
  • 2022NOIPA层联测10 10月17日
    一句话总结:T1不会,T2多\(\log\)而且写挂了,T3T4没看,56分离场。部分题解T1.异或(xor)推了一大堆没用的结论,没想到分治。题解:从高位到低位处理,对于每一层,如果当前这段......
  • 【LeetCode】面试题 17.04. 消失的数字(C++)
    面试题17.04.消失的数字(C++)​​1题目描述​​​​2示例描述​​​​2.1示例1​​​​2.2示例2​​​​3解题思路​​​​4源码详解(C++)​​1题目描述数组nums包含从......
  • 【LeetCode】1758. 生成交替二进制字符串的最少操作数(C++)
    1758.生成交替二进制字符串的最少操作数(C++)​​1题目描述​​​​2示例描述​​​​2.1示例1​​​​2.2示例2​​​​2.3示例3​​​​3解题提示​​​​4解题思路......