CF940E. Cashback [贪心+dp]

CF940E - 最小现金回馈算法解析
这是一道来自Codeforces的题目,要求找到数组分割成连续子数组后的最小价值总和,其中子数组价值为其元素之和减去最小w个数的和。文章介绍了贪心策略和动态规划的解题思路,提供了最优分割方法的解释和转移方程的细节。

E Cashback
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Since you are the best Wraith King, Nizhniy Magazin «Mir» at the centre of Vinnytsia is offering you a discount.

You are given an array a of length n and an integer c.

The value of some array b of length k is the sum of its elements except for the smallest. For example, the value of the array [3, 1, 6, 5, 2] with c = 2 is 3 + 6 + 5 = 14.

Among all possible partitions of a into contiguous subarrays output the smallest possible sum of the values of these subarrays.

Input
The first line contains integers n and c (1 ≤ n, c ≤ 100 000).

The second line contains n integers ai (1 ≤ ai ≤ 109) — elements of a.

Output
Output a single integer — the smallest possible sum of values of these subarrays of some partition of a.

Examples
inputCopy
3 5
1 2 3
outputCopy
6
inputCopy
12 10
1 1 10 10 10 10 10 10 9 10 10 10
outputCopy
92
inputCopy
7 2
2 3 6 4 5 7 1
outputCopy
17
inputCopy
8 4
1 3 4 5 5 3 4 1
outputCopy
23
Note
In the first example any partition yields 6 as the sum.

In the second example one of the optimal partitions is [1, 1], [10, 10, 10, 10, 10, 10, 9, 10, 10, 10] with the values 2 and 90 respectively.

In the third example one of the optimal partitions is [2, 3], [6, 4, 5, 7], [1] with the values 3, 13 and 1 respectively.

In the fourth example one of the optimal partitions is [1], [3, 4, 5, 5, 3, 4], [1] with the values 1, 21 and 1 respectively.

题意:给一个有n个元素的序列,可以任意分割成若干个序列,每个序列的价值=元素总和-序列内最小的w个数的和(其中w是序列长度/c下取整),给出n和原序列以及c的值,求总价值的最小值

题解:总价值的最小值就相当于让减去的数字之和尽可能大,而显然将序列分解成若干个长度为c的序列之和能去掉的最小值之和最大,因为两个长度为c的序列的两个最小值之和一定不小于一个长度为2c的序列的最小值+次小值。接下来很容易用当前元素i是否和前c-1个元素结合成一个序列写转移方程

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" is "<<x<<endl;
const int maxn=1e5+5;
ll a[maxn],dp[maxn],sum[maxn];
int main(){
    int n,c;
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;i++){scanf("%lld",&a[i]);sum[i]=sum[i-1]+a[i];}
    multiset<ll>st;
    for(int i=1;i<=n;i++)dp[i]=1e16;
    for(int i=1;i<=n;i++){
        st.insert(a[i]);
        dp[i]=min(dp[i],dp[i-1]+a[i]);
        if(i>=c){
            dp[i]=min(dp[i],dp[i-c]+sum[i]-sum[i-c]-*(st.begin()));
            st.erase(st.find(a[i-c+1]));
        }
    }
    printf("%lld\n",dp[n]);
    return 0;
}

<think>嗯,用户现在遇到了在Java中使用Bouncy Castle库时,SECNamedCurves.getByName("sm2p256v1")返回null的问题。我需要先回想一下之前给他的解决方案,以及他提供的引用内容。之前我给出的代码中使用了SM2Util类来定义DOMAIN_PARAMS,其中用到了SECNamedCurves.getByName("sm2p256v1")。用户现在的问题是这个方法返回null,导致程序无法正常运行。 首先,我应该考虑为什么SECNamedCurves.getByName("sm2p256v1")会返回null。可能的原因有几个: 1. **Bouncy Castle版本问题**:用户可能使用的是较旧的BC版本,其中不包含SM2曲线参数。SM2作为国密算法,可能在旧版本中没有被正确支持。例如,BC的1.60及以下版本可能没有内置SM2的曲线参数。 2. **曲线名称不正确**:不同的BC版本可能对曲线名称有不同的命名规范。例如,有些版本可能需要使用"sm2p256v1"之外的名称,比如"curveSM2"或者其他别名。 3. **提供者未正确注册**:虽然用户之前的代码中已经添加了BouncyCastleProvider,但可能在获取曲线时没有正确加载,或者存在多个版本的BC库导致冲突。 接下来,我需要结合用户提供的引用内容。引用[1]中提到了处理加密时的异常捕获,引用[2]涉及前端JSP引入SM2相关的JS库,这可能与前后端交互有关,但用户当前的问题是关于后端Java代码中曲线获取的问题。因此,主要需要关注BC库的配置和使用。 根据之前给出的代码示例,用户可能在SM2Util类中使用了SECNamedCurves来获取曲线参数,但现在这个方法返回null。可能的解决步骤包括: - **升级Bouncy Castle版本**:建议用户检查当前使用的BC版本,并升级到支持SM2的较新版本,如1.68或更高。新版本通常会包含更多国密算法的支持。 - **手动注册SM2曲线参数**:如果升级版本不可行,可能需要手动将SM2的曲线参数添加到BC的曲线列表中。这可以通过调用SECNamedCurves.defineCurve()方法,并传入相应的椭圆曲线参数来实现。例如,手动定义sm2p256v1的各个参数,如素数p、系数a、b、基点G、阶n等。 - **使用不同的曲线名称**:检查是否存在拼写错误,或者尝试其他可能的名称,比如"curveSM2"或"sm2"等,不同版本的BC可能有不同的命名方式。 - **确保正确初始化**:确认在访问曲线参数之前,Bouncy Castle提供者已经被正确注册,并且相关类已经被加载。可能需要显式调用某个初始化方法,或者在静态代码块中提前加载所需的曲线。 另外,用户提到的引用[2]中涉及到前端引入sm2.js等库,这可能意味着用户需要前后端使用相同的曲线参数,否则可能导致加解密不兼容的问题。但在当前问题中,主要是后端Java代码的问题,所以暂时可以忽略前端部分,专注于BC库的配置。 总结可能的解决方案: 1. 升级Bouncy Castle到支持SM2曲线的版本。 2. 手动注册SM2曲线参数到SECNamedCurves中。 3. 检查曲线名称是否正确,尝试不同的名称。 4. 确保BC提供者正确注册,没有版本冲突。 在编写回答时,需要逐步引导用户检查这些可能性,并提供具体的代码示例,如如何手动注册曲线参数,或者如何检查当前BC版本。同时,要注意代码的正确性,比如在手动注册时,需要正确填写SM2的椭圆曲线参数,这些参数可以从国密标准文档或BC的源代码中找到。 另外,还需要提醒用户注意依赖冲突,比如项目中可能存在多个不同版本的BC库,导致类加载异常。可以通过Maven或Gradle的依赖树检查是否存在版本冲突,并排除旧版本。 最后,如果用户的问题仍然无法解决,可能需要更详细的错误日志或环境信息,以进一步诊断问题。</think>以下是在Java中解决`SECNamedCurves.getByName("sm2p256v1")`返回null问题的完整方案,结合Bouncy Castle库的版本适配和曲线参数手动注册方法: --- ### 一、问题原因分析 1. **旧版本兼容问题**:Bouncy Castle 1.60及更早版本未内置国密SM2曲线参数[^1] 2. **曲线名称不匹配**:不同BC版本对椭圆曲线名称的标识符定义不同 3. **依赖冲突**:项目中可能存在多个BC版本导致类加载异常 --- ### 二、解决方案分步实施 #### 方案1:升级Bouncy Castle(推荐) ```xml <!-- Maven依赖配置(使用1.70+版本) --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> <!-- 2023年最新为1.76 --> </dependency> ``` 验证升级后效果: ```java // 检查曲线参数是否可用 System.out.println(SECNamedCurves.getByName("sm2p256v1")); // 应输出非null ``` #### 方案2:手动注册曲线参数(兼容旧版本) ```java import org.bouncycastle.asn1.sec.SECNamedCurves; import org.bouncycastle.asn1.sec.SECObjectIdentifiers; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; public class SM2CurveRegistrar { static { // 手动注册SM2曲线参数(GB/T 32918.5-2017) if (SECNamedCurves.getByName("sm2p256v1") == null) { SECNamedCurves.defineCurve("sm2p256v1", SECObjectIdentifiers.sm2p256v1, createSM2Params()); } } private static X9ECParameters createSM2Params() { // 国密SM2椭圆曲线参数 BigInteger p = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16); BigInteger a = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16); BigInteger b = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16); byte[] S = Hex.decode("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"); BigInteger gx = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16); BigInteger gy = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16); BigInteger n = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16); BigInteger h = BigInteger.valueOf(1); ECCurve curve = new ECCurve.Fp(p, a, b, n, h); ECPoint G = curve.createPoint(gx, gy); return new X9ECParameters(curve, G, n, h, S); } // 初始化时调用 public static void init() { // 触发静态块执行 } } ``` 使用方式: ```java // 在程序启动时注册 SM2CurveRegistrar.init(); ``` --- ### 三、关键验证步骤 1. **版本检查代码**: ```java public static void checkBCVersion() { System.out.println("BouncyCastle Provider Version: " + Security.getProvider("BC").getVersion()); } // 应输出1.60以上版本号 ``` 2. **曲线名称兼容性测试**: ```java void testCurveNames() { testName("sm2p256v1"); // 国家标准名称 testName("curveSM2"); // 某些版本的别名 testName("secp256r1"); // 国际标准名称(与SM2参数不同) } private void testName(String name) { System.out.println(name + " exists: " + (SECNamedCurves.getByName(name) != null)); } ``` --- ### 四、常见问题排查 1. **依赖冲突检测(Maven)**: ```bash mvn dependency:tree -Dincludes=org.bouncycastle ``` 确保输出中仅存在单个bcprov-jdk15on的高版本 2. **运行时加载验证**: ```java public static void checkLoadedClass() throws Exception { Class<?> clazz = Class.forName("org.bouncycastle.asn1.sec.SECNamedCurves"); URL location = clazz.getProtectionDomain().getCodeSource().getLocation(); System.out.println("BC实际加载路径: " + location); } ``` --- ### 五、备选方案 如果仍无法解决,可直接使用硬编码参数: ```java public static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters( new ECCurve.Fp( new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16), // p new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16), // a new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16), // b new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16), // n BigInteger.ONE // h ), new ECPoint.Fp( new ECFieldElement.Fp( new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16), new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16) ), new ECFieldElement.Fp( new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16), new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16) ) ), new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16) ); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值