feat: 添加三个算法题目解决方案

添加P14359、P14358和P14360三个题目的C++实现代码
P14359实现异或操作计数功能
P14358解决矩阵中元素定位问题
P14360使用动态规划计算合法子集数
This commit is contained in:
Zengtudor 2025-11-08 16:05:33 +08:00
parent 712609a466
commit 3abd9891ef
3 changed files with 168 additions and 0 deletions

42
src/11/6/P14358.cpp Normal file
View File

@ -0,0 +1,42 @@
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <functional>
#include <iostream>
#include <istream>
using ll = int64_t;
#define printf
const ll maxn = 17;
ll isd=1;
ll n,m,x=1,y=1,ansx,ansy,ansn,a[maxn*maxn];
int main(){
std::iostream::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin>>n>>m;
for(ll i=1;i<=n*m;i++){
std::cin>>a[i];
}
ansn=a[1];
std::sort(a+1,a+1+n*m,std::greater<>());
ll tot=1;
while(y<=m){
printf("x=%lld, y=%lld\n",x,y);
if(x==n+1||x==0){
y++;
isd=isd*-1;
x+=isd;
continue;
}
ll tmp=a[tot++];
printf("tmp=%lld\n",tmp);
if(tmp==ansn){
ansx=x,ansy=y,ansn=tmp;
break;
}
x+=isd;
}
std::cout<<ansy<<" "<<ansx<<"\n";
}

40
src/11/7/P14359.cpp Normal file
View File

@ -0,0 +1,40 @@
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <istream>
using ll = int64_t;
#define printf
const ll p220=1048576,maxa=p220+7;
ll n,k,f[maxa],now,tmp,ans,last;
struct S{
ll l,r;
};
int main(){
std::iostream::sync_with_stdio(false);
std::cin.tie(nullptr);
for(ll i=0;i<maxa;i++){
f[i]=-1;
}
std::cin>>n>>k;
f[0]=1;
last=0;
for(ll i=1;i<=n;i++){
std::cin>>tmp;
now^=tmp;
printf("i=%lld, now=%lld\n",i,now);
printf("f[%lld]=%lld\n",now^k,f[now^k]);
if(f[now^k]!=-1){
if(f[now^k]>last){
ans++;
last=i;
}
printf("add %lld, %lld\n",f[now^k],i);
f[now^k]=-1;
}
f[now]=i+1;
}
std::cout<<ans<<"\n";
}

86
src/11/7/P14360.cpp Normal file
View File

@ -0,0 +1,86 @@
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
// 使用标准 long long 类型,并定义常量
using ll = long long;
const int MOD = 998244353;
const int MAXN = 5005;
// 预计算2的幂用于快速得到子集总数
ll p2[MAXN];
void precompute_powers(int n) {
p2[0] = 1;
for (int i = 1; i <= n; ++i) {
p2[i] = (p2[i - 1] * 2) % MOD;
}
}
int main() {
// OI/ACM 风格的快速输入输出
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> a(n);
int total_sum = 0;
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
total_sum += a[i];
}
// 1. 排序:这是算法的关键前提
std::sort(a.begin(), a.end());
// 预计算2的幂
precompute_powers(n);
// 2. DP 数组设置
// dp[j] 表示从当前已处理的木棍中选出若干根,使其和为 j 的方案数。
// 背包容量上界是所有木棍的总和。
std::vector<ll> dp(total_sum + 1, 0);
dp[0] = 1; // 和为0的方案只有一种不选任何木棍
ll totans = 0;
int cursum = 0; // 记录当前处理过的木棍的总和作为DP容量的上界
// 3. 主循环:依次处理每根木棍
for (int i = 0; i < n; ++i) {
// a[i] 是当前木棍的长度
// 3.1 统计答案:
// 假设 a[i] 是最长边,从前面的 a[0]...a[i-1] 中选边。
// 此时 dp 数组存储的是从 {a[0], ..., a[i-1]} 中选择的方案。
// 我们需要找到满足 sum(S) > a[i] 的子集 S 的数量。
// 计算 sum(S) <= a[i] 的方案数
ll nans = 0;
// 注意 j 的上界是 cursum 和 a[i] 的较小值
for (int j = 0; j <= std::min(cursum, a[i]); ++j) {
nans = (nans + dp[j]) % MOD;
}
// 从 {a[0], ..., a[i-1]} 中选子集,总方案数是 2^i
ll totpre = p2[i];
// 合法方案数 = 总方案数 - 不合法方案数 (sum(S) <= a[i])
ll ok = (totpre - nans + MOD) % MOD;
// 累加到最终答案
totans = (totans + ok) % MOD;
// 3.2 更新DP数组
// 将 a[i] 加入可选木棍池,为后续 a[i+1], a[i+2]... 作为最长边时做准备。
cursum += a[i];
// 0/1 背包,必须逆序遍历以保证每个物品只被选一次
for (int j = cursum; j >= a[i]; --j) {
dp[j] = (dp[j] + dp[j - a[i]]) % MOD;
}
}
std::cout << totans << std::endl;
}