AT_abc408_d [ABC408D] Flip to Gather题解

题目描述

给你一个长度为 N 的、由 0 和 1 构成的字符串 S。

你可以执行以下操作若干次:

  • 选择一个整数 1≤i≤N,Si​←1−Si​。

你的目标是让 S 中的 1 连续或 S 中不存在 1。请找出需要的最小的操作次数。

多组数据。

输入格式

多组数据。第一行一个整数 T(1≤T≤2×104),表示数据组数。

对于每组数据:
第一行一个整数 N(1≤N≤2×105)。
第二行一个长为 N 的字符串 S。S 由 0 和 1 构成。

保证单个测试点中 ∑N≤2×105。

输出格式

对于每组数据,输出一行一个整数表示答案。

输入输出样例

输入 #1

3
5
10011
10
1111111111
7
0000000 

输出 #1

1
0
0

输入 #2

5
2
01
10
1000010011
12
111100010011
3
111
8
00010101

输出  #2

0
2
3
0
2

通过观察和手玩样例可以发现,对于任意区间 [l, r) 可以分为区间内和区间外的操作:

区间内:将区间内的 0 都转换为 1,

区间外:将 1 转换为 0。

总操作次数 =(区间长度)+(总的数字 1 的个数)- 2 *(区间内 1 的个数)。

因此我们可以想到用前缀和的方法来维护:

用 a[i] 维护字符串前 i 位中 1 的个数,

用 b[i] 维护 b[i] = i - 2 * a[i]。

此时总操作次数为 cnt+b[r]−b[l],但复杂度 O(n^2) 仍无法通过。注意到我们可以固定右端点 r,并选择最优的左端点 l 来优化。

具体地:

构建后缀最小值数组 c[i],其中 c[i]=minj≥i​b[j]。

枚举左端点 l,利用 c 数组快速得到最小化的 b[r]−b[l] 值。

这样可将复杂度优化至 O(n),遍历一遍即可求出答案。代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<unordered_map>
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
#define MAXN 1000100
int a[MAXN],b[MAXN],c[MAXN];
void solve(){
	int n;
	cin>>n;
	for(int i=0;i<=n+5;i++)a[i]=b[i]=c[i]=0;
	string s;
	cin>>s;
	s=" "+s;
	for(int i=1;i<=n;i++){
		if(s[i]=='1')a[i]++;
		a[i]+=a[i-1];
	}
	int cnt=a[n];
	for(int i=1;i<=n;i++)b[i]=i-2*a[i];
	for(int i=1;i<=n;i++)c[i]=b[i];
	for(int i=n-1;i>=0;i--)c[i]=min(c[i+1],b[i]);
	int mi=0x3f3f3f3f;
	for(int i=0;i<=n;i++){
		mi=min(mi,cnt+c[i]-b[i]);
	}
	cout<<mi<<endl;
}
signed main(){
	ios;
	int t=1;
	cin>>t;
	while(t--)
	solve();
	return 0;
}

第一次发博客,有什么不好的还请各位大佬指点指点

<think>好的,我现在需要处理用户提供的微信支付订单查询时遇到的错误响应。错误信息显示签名字段必填性校验失败,也就是签名缺失或者不正确。用户之前已经询问过如何查询订单,现在遇到了问题,需要帮助解决。 首先,我要分析错误信息。返回的XML显示return_code是FAIL,return_msg指出“输入源‘/body/xml/sign’映射到字段‘签名’必填性规则校验失败,此字段为必填项”。这说明请求中没有包含sign字段,或者该字段的值不符合微信的校验规则。 接下来,我需要考虑可能的原因。常见的情况包括:请求的XML中确实没有包含sign节点;签名生成算法有误导致签名无效;参数排序或拼接错误;或者密钥错误导致签名不匹配。此外,还有可能是XML格式不正确,例如节点名称错误或者编码问题。 然后,我需要针对每个可能的原因给出解决方案。首先检查请求XML是否包含sign节点,并确保节点名称正确。接着,验证签名生成过程是否正确,包括参数按ASCII排序、正确拼接密钥、使用MD5生成签名并转换为大写。同时,检查APIv2密钥是否正确,没有多余的空格或字符。还要确保XML的格式正确,比如使用正确的CDATA包裹,以及正确的Content-Type头。 另外,用户之前提供的APIv2密钥是e2c95ab8885e4192a6631cf2cece408d,需要确认是否正确无误。可能用户输入时存在拼写错误或者复制了多余的空格。同时,提醒用户注意密钥的保密,避免泄露。 还需要考虑用户是否在请求中同时使用了transaction_id和out_trade_no,根据微信文档,这两个参数二选一即可,同时使用可能导致错误。此外,随机字符串nonce_str是否每次请求都重新生成,避免重复使用导致的问题。 最后,建议用户使用微信提供的在线验签工具进行调试,或者提供代码示例中的签名生成步骤,帮助用户逐步排查问题。如果问题依然存在,建议检查网络请求是否正常,或者联系微信支付技术支持获取进一步帮助。 在回答中需要结构清晰,分点列出可能的原因和解决方案,使用用户容易理解的语言,避免过多技术术语。同时,注意使用正确的LaTeX格式,确保数学表达式和代码块正确显示。最后,提醒用户升级到APIv3以提高安全性,并提供错误代码速查,方便用户快速定位问题。</think>$\boxed{\text{微信支付签名错误解决方案}}$ **错误信息解析:** ```xml <return_code>FAIL</return_code> <return_msg>输入源“/body/xml/sign”映射到字段“签名”必填性规则校验失败</return_msg> ``` $\boxed{I. \text{错误原因诊断}}$ 1. 核心问题公式表达: $$ \exists \text{缺失项} \in \begin{cases} \text{请求未携带sign参数} \\ \text{签名参数值为空} \\ \text{XML节点命名错误} \quad (\text{如大小写错误}) \end{cases} $$ 2. 常见触发场景: ```mermaid graph TD A[请求构造异常] --> B{具体表现} B -->|场景1| C[XML缺少<sign>节点] B -->|场景2| D[签名生成算法错误] B -->|场景3| E[参数编码格式错误] ``` $\boxed{II. \text{紧急修复步骤}}$ 1. XML结构验证: ```diff <xml> <appid>wx0e86a074a1814251</appid> <mch_id>1699250279</mch_id> + <sign>VALID_SIGNATURE</sign> <!-- 必须添加的签名节点 --> ... </xml> ``` 2. 签名算法二次验证: - 参数排序公式: $$ \text{排序规则} = \text{ASCII}(k_1) < \text{ASCII}(k_2) < ... < \text{ASCII}(k_n) $$ - 正确拼接示例: ```python # 错误示例:遗漏商户号参数 stringA = "appid=wx0e86a...&nonce_str=123456" # 正确示例:包含所有必填参数 stringA = "appid=wx0e86a...&mch_id=1699250279&nonce_str=123456..." ``` $\boxed{III. \text{调试工具推荐}}$ 1. 在线验签工具: $$ \text{微信官方验证地址:} \href{https://pay.weixin.qq.com/wiki/tools/signverify/}{签名验证工具} $$ 2. Postman调试模板: ```json { "url": "https://api.mch.weixin.qq.com/pay/orderquery", "method": "POST", "header": { "Content-Type": "text/xml" }, "body": "<xml>...</xml>" } ``` $\boxed{IV. \text{代码修正示例}}$ ```python # 修正后的签名生成函数 def generate_sign(params, api_key): sorted_params = sorted(params.items(), key=lambda x: x[0]) stringA = '&'.join([f"{k}={v}" for k,v in sorted_params]) stringSignTemp = stringA + f"&key={api_key}" # 解决中文编码问题 if any(isinstance(v, str) and re.search(u'[\u4e00-\u9fa5]', v) for v in params.values()): stringSignTemp = stringSignTemp.encode('utf-8') return hashlib.md5(stringSignTemp).hexdigest().upper() # 确保在最终XML中包含签名节点 xml_template = f""" <xml> ... <sign>{generated_sign}</sign> <!-- 必须保持节点名称全小写 --> </xml> """ ``` $\boxed{V. \text{高级排查指南}}$ 1. 字符编码检查表: | 参数类型 | 编码要求 | 常见错误 | |---------|--------------|---------------| | 中文字符 | UTF-8 | GBK编码导致签名错误 | | 特殊符号 | URLEncode处理 | 未转义&符号 | 2. 密钥有效性验证: ```bash # 使用OpenSSL验证密钥格式 echo -n "原始字符串" | openssl md5 -hex -sigopt rsa_padding_mode:pkcs1 ``` $\boxed{\text{补充说明}}$ 若问题仍未解决,可通过以下方式获取交易流水号辅助排查: $$ \text{交易追踪ID} = \text{商户号}(1699250279) + \text{YYYYMMDDHHMMSS} + \text{随机6位数字} $$ 建议在代码中添加预校验机
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值