mirror of
https://gitcode.com/Zengtudor/alg2025.git
synced 2025-12-16 04:03:01 +00:00
feat: 添加三个算法题目解决方案
添加P14359、P14358和P14360三个题目的C++实现代码 P14359实现异或操作计数功能 P14358解决矩阵中元素定位问题 P14360使用动态规划计算合法子集数
This commit is contained in:
parent
712609a466
commit
3abd9891ef
42
src/11/6/P14358.cpp
Normal file
42
src/11/6/P14358.cpp
Normal 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
40
src/11/7/P14359.cpp
Normal 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
86
src/11/7/P14360.cpp
Normal 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;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user