Neither AB nor BA,AtCoder Grand Contest 040,巧妙的构造

Portal 题解:奇偶位替换与组合计数
本文深入解析了一个名为Portal的编程挑战题解,通过奇数位与偶数位字符的替换策略,巧妙地解决了不能删除相同字符的问题。文章详细阐述了解题思路,即通过判断A和B的数量关系来确定解的存在性,并利用组合数学中的技巧计算可能的解的总数。最后,提供了完整的C++代码实现。

正题

      Portal

      题解太巧妙了

      我们把奇数位上的A换成B,B换成A。就变成了现在不能删除AA和BB,因为删除两位 剩下位的奇偶是不变的,所以就有唯一对应的A和B。

      考虑一个性质,如果A的个数或者B的个数>\frac{n}{2},那么就无解,反之有解。

      感觉挺显然的,考虑A的话,把B和C染黑就好了,反之亦然,发现异色才能抵消,那么>\frac{n}{2}显然无解,否则肯定可以消除掉。

      那么就可以直接补集转化了,枚举A或B的个数,直接算贡献就好了。

#include<bits/stdc++.h>
using namespace std;

const int N=10000010;
int n;
int fac[N],inv[N],ci[N];
const long long mod=998244353;

long long ksm(long long x,long long t){
	long long tot=1;
	while(t){
		if(t&1) (tot*=x)%=mod;
		(x*=x)%=mod;
		t/=2;
	}
	return tot;
}

long long C(int x,int y){
	return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
}

int main(){
	scanf("%d",&n);
	long long tot=0;
	fac[0]=ci[0]=1;for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod,ci[i]=ci[i-1]*2%mod;
	inv[n]=ksm(fac[n],mod-2);for(int i=n-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
	for(int i=n/2+1;i<=n;i++) tot+=C(n,i)*ci[n-i]%mod;
	printf("%lld\n",(ksm(3,n)-tot*2%mod+mod)%mod);
}

 

在编译 GCC 4.6 时遇到的错误信息 `subscripted value is neither array nor pointer nor vector` 通常表明代码中存在类型错误。具体来说,尝试对一个既不是数组、也不是指针或向量的值进行下标操作会导致此类错误。此问可能源于源代码中的语法错误、类型定义错误,或者是 GCC 编译器自身的 bug,尤其是在较旧版本中。 在 GCC 的某些版本中,特别是在处理复杂的类型定义或宏展开时,可能会出现误报此类错误的情况。例如,在 `gtype-desc.c` 文件的第 8829 行,错误可能与对某种结构体或联合体的字段进行了非法的数组访问有关。如果该字段本身不是数组、指针或向量类型,编译器会报错[^1]。 ### 常见原因 1. **类型定义错误**:访问的变量可能被错误地声明为非数组、非指针类型。 2. **宏展开问**:宏定义可能在特定上下文中展开为非法的表达式。 3. **编译器 bug**:GCC 4.6 可能在某些特定的代码结构下无法正确处理下标操作。 4. **代码逻辑错误**:开发者可能在不经意间对非容器类型进行了下标访问。 ### 解决方法 1. **检查变量类型**: 确保进行下标操作的变量确实是数组、指针或向量类型。例如,以下代码会引发此类错误: ```c struct example { int data; }; struct example arr[10]; int value = arr[0]; // 错误:arr[0] 是 struct example 类型,而非 int ``` 正确的做法是访问结构体内部的字段: ```c int value = arr[0].data; // 正确 ``` 2. **查看宏定义**: 检查涉及下标操作的宏定义是否在特定上下文中展开为无效代码。例如,宏可能在某些条件下展开为非指针类型。 3. **更新 GCC 版本**: 如果问是由于编译器 bug 导致的,建议升级到更新的 GCC 版本。GCC 4.6 是一个较老的版本,许多此类问在后续版本中已得到修复。 4. **修改源代码**: 如果无法升级编译器,可以尝试修改源代码中引发错误的部分,确保所有下标操作的对象都具有正确的类型。 5. **启用调试信息**: 使用 `-E` 选项预处理源文件,查看宏展开后的实际代码,有助于定位问。 ### 示例修正 假设在代码中存在如下错误: ```c int *ptr = 42; int value = ptr[0]; // 错误:ptr 被赋值为整数,而非指向有效内存 ``` 修正方式应为: ```c int arr[] = {42}; int *ptr = arr; int value = ptr[0]; // 正确 ``` ### 编译建议 在编译过程中,建议使用 `-Wall -Wextra` 选项启用更多警告,以帮助发现潜在问。此外,使用 `make V=1` 可以查看详细的编译命令,便于调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值