Vibe Coding…

User

1
2
3
4
5
6
7
8
9
10
250250

在集合{1^1, 2^2, 3^3,…, 250250^{250250}}的所有子集中,有些非空子集的元素和能够被250整除,求这样的子集的数目。输入这个数的后十六位作为你的答案。

我的思路:背包dp.
后十六位可以理解为对1e16取模,被250整除可以理解为一个250模数的背包.

可以用快速幂计算这个数字(模250),然后用这个数字当成新循环节更新原先的所有答案.
使用滚动数组,复杂度O(250250*250)完全能过.
请使用c++实现,给出代码.

GPT(降智)

1
2
3
4
5
6
7
8
9
10
11
下面给出一个直接按你思路实现的 C++ 程序。

思路简要说明(更正与确认):

* 用长度为 250 的背包 `dp[r]` 表示当前已考虑的元素下,和对 250 取模为 `r` 的子集个数(包括空集)。
* 初始 `dp[0]=1`(空集)。
* 对每个 `i=1..250250`,计算 `v = i^i % 250`(快速幂),然后转移:
`dp2[r] = dp[r] + dp[(r-v+250)%250]`(选择或不选择当前元素),同时对 `MOD = 10^16` 取模以保持仅保存后 16 位。
* 最后答案为 `dp[0] - 1`(去掉空集),输出为 16 位(不足位补零)。

下面代码已做性能优化(使用固定数组、在每步用临时数组更新),能在合理时间内跑完(约 `250250*250 ≈ 6.25e7` 次简单操作)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <bits/stdc++.h>
using namespace std;

int main(){
const int N = 250250;
const int M = 250;
const unsigned long long MOD = 10000000000000000ULL; // 1e16

// dp[r] = number of subsets (mod MOD) with sum % 250 == r
vector<unsigned long long> dp(M, 0), ndp(M, 0);
dp[0] = 1; // empty subset

// fast pow modulo 250
auto modpow = [](unsigned long long a, unsigned long long e)->int{
unsigned long long base = a % 250;
unsigned long long res = 1 % 250;
while(e){
if(e & 1) res = (res * base) % 250;
base = (base * base) % 250;
e >>= 1;
}
return (int)res;
};

for(int i = 1; i <= N; ++i){
int v = modpow((unsigned long long)i, (unsigned long long)i); // i^i % 250
// ndp[r] = dp[r] (not take) + dp[(r - v) mod 250] (take)
// compute with 128-bit intermediate to be safe, then mod 1e16
for(int r = 0; r < M; ++r){
int from = r - v;
if(from < 0) from += M;
unsigned __int128 sum = (unsigned __int128)dp[r] + (unsigned __int128)dp[from];
unsigned long long val = (unsigned long long)(sum % MOD);
ndp[r] = val;
}
dp.swap(ndp);
// no need to clear ndp fully; will be overwritten next iter
}

unsigned long long ans = dp[0];
if(ans == 0) ans = (MOD - 1); // dp[0] - 1 mod MOD
else ans = (ans + MOD - 1) % MOD;

// print last 16 digits with leading zeros
// use printf to ensure fixed width
printf("%016llu\n", ans);
return 0;
}
1
把这份代码用 g++ -O2 编译并运行即可得到要求的后十六位输出。如果你希望我直接运行并给出具体的 16 位数字结果,请告诉我(注意我不能在本地机器运行,但可以指导你如何运行)。

fact

GPT一发过了.