比赛链接
S 老师的公式
输入一个数n[1, 1e6],求
我的思路,分为奇数和偶数两种情况
如果 n 是奇数,n + 1 一定是偶数, 且(n + 1) / 2 属于n!
如果 n 是偶数,n + 1 一定是奇数, 且 n / 2 属于n!, 但是n + 1不一定属于n!
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
// 获取一个数的所有质因数
vector<ll> getAllPrimeFactors(ll N) {
vector<ll> result;
for (int i = 2; i * i <= N; i++) {
while (N % i == 0) { // 如果 i 能够整除 N,说明 i 为 N 的一个质因子。
result.push_back(i); // 在这里添加 i,确保重复的质因数也被记录
N /= i;
}
}
if (N != 1) { // 说明再经过操作之后 N 留下了一个素数
result.push_back(N);
}
return result;
}
void solve(ll n) {
// 计算1+2+...+n
ll sum = n * (n + 1) / 2;
if (n % 2 == 0) {
// 如果 n 是偶数,n + 1 一定是奇数, 且 n / 2 属于n!, 但是n + 1不一定属于n!
// 所以我们需要找到 n + 1 的所有质因数,然后去掉 n / 2 和 n + 1
vector<ll> v = getAllPrimeFactors(n + 1);
ll tm = 1;
for (auto it: v) {
if (it == n / 2 || it == n + 1) continue;
tm *= it;
}
cout << n / 2 * tm << endl;
} else if (n % 2 == 1) {
// 如果 n 是奇数,n + 1 一定是偶数, 且(n + 1) / 2 属于n!
// 所以答案是 (n + 1) / 2 * n
cout << sum << endl;
}
}
int main() {
ll n;
cin >> n;
solve(n);
}
其他思路,
不停取模得到答案
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll n;
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
int main() {
cin >> n;
ll a = n * (n + 1) / 2;
ll prod = 1;
for (int i = 1; i <= n; i++) {
prod = prod * i % a;
}
ll ans = gcd(prod, a);
cout << ans << endl;
return 0;
}
S 老师的签到
爆内存
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6 + 10;
ll n, m;
string solve(int n, int m, vector<string> &M) {
vector<vector<string>> dp(n, vector<string>(m, ""));
// dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + M[i][j]
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
char s = M[i][j];
if (i > 0 && j > 0) {
if (dp[i - 1][j] < dp[i][j - 1]) {
dp[i][j] = dp[i - 1][j] + s;
} else {
dp[i][j] = dp[i][j - 1] + s;
}
} else if (i > 0) {
dp[i][j] = dp[i - 1][j] + s;
} else if (j > 0) {
dp[i][j] = dp[i][j - 1] + s;
} else {
dp[i][j] = s;
}
}
}
return dp[n - 1][m - 1];
}
int main() {
cin >> n >> m;
vector<string> M(n);
for (int i = 0; i < n; i++) {
cin >> M[i];
}
cout << solve(n, m, M) << endl;
return 0;
}
优化,注意到dp**[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + M[i][j], 只遇到上一个和前一个状态,可以优化成一维。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6 + 10;
ll n, m;
string solve(int n, int m, vector<string> &M) {
vector<string> dp(m);
dp[0] = M[0][0];
for (int i = 1; i < m; i++) {
dp[i] = dp[i - 1] + M[0][i];
}
for (int i = 1; i < n; i++) {
dp[0] += M[i][0];
for (int j = 1; j < m; j++) {
dp[j] = min(dp[j], dp[j - 1]) + M[i][j];
}
}
return dp[m - 1];
}
int main() {
cin >> n >> m;
vector<string> M(n);
for (int i = 0; i < n; i++) {
cin >> M[i];
}
cout << solve(n, m, M) << endl;
return 0;
}
S 老师的求和
由于答案可能很大,你只需要输出对 998244353998244353 取模的结果
推公式
#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
typedef long long ll;
ll a, b, x, t;
// 快速幂算法,计算 base^exponent % MOD
ll fastPow(ll base, ll exponent, ll MOD) {
ll result = 1;
base %= MOD;
while (exponent > 0) {
if (exponent & 1) result = (result * base) % MOD;
base = (base * base) % MOD;
exponent >>= 1;
}
return result;
}
// 计算逆元,这里 a 是要求逆元的数
ll modInverse(ll a, ll MOD) {
return fastPow(a, MOD - 2, MOD); // 费马小定理
}
ll f1(ll n) {
return (a * n + b) % MOD;
}
// 等差数列求和
ll f2(ll n) {
return (n * b + a * (n + 1) % MOD * n % MOD * modInverse(2, MOD) % MOD) % MOD;
}
// n(n+1)(a(2n+1)+3a+6b) / 12
ll f3(ll n) {
return n % MOD * (n + 1) % MOD * (a % MOD * (2 * n % MOD + 1) % MOD + 3 * a % MOD + 6 * b % MOD) % MOD *
modInverse(12, MOD) % MOD;
}
ll f4(ll n) {
// x(x+1)(3ax(x+1)+4a(2x+1)+9a+18b) / 6
ll res = 0;
// res += a * n * n * (n + 1) * (n + 1) / 2;
res += a % MOD * n % MOD * n % MOD * (n + 1) % MOD * (n + 1) % MOD * modInverse(2, MOD) % MOD;
// res += (6 * a + 6 * b) * n * (n + 1) * (2 * n + 1) / 6;
res += (6 * a % MOD + 6 * b % MOD) * n % MOD * (n + 1) % MOD * (2 * n + 1) % MOD * modInverse(6, MOD) % MOD;
// res += (4 * a + 6 * b) * n * (n + 1) / 2;
res += (4 * a % MOD + 6 * b % MOD) * n % MOD * (n + 1) % MOD * modInverse(2, MOD) % MOD;
res = res * modInverse(12, MOD) % MOD;
return res;
}
int main() {
cin >> t;
cin >> a >> b >> x;
cout << f1(x) << ' ' << f2(x) << ' ' << f3(x) << ' ' << f4(x) << endl;
}
其他解法
#include <bits/stdc++.h>
using namespace std;
const int N = 1e8 + 10, mod = 998244353;
// inv is the inverse of 1, 2, 3, 4
int inv[] = {1, 499122177, 166374059, 291154603};
int a, b;
long long L(int i, int k) {
// i == 0
// ans = inv[0] * (a * k + b)
// i == 1
int ans = 1ll * inv[i] * ((1ll * a * k + 1ll * i * a + 1ll * (i + 1) * b) % mod) % mod;
for (int j = 0; j < i; ++j)
ans = 1ll * ans * (k + j) % mod;
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--) {
int k;
cin >> a >> b >> k;
cout << L(0, k) << " " << L(1, k) << " " << L(2, k) << " " << L(3, k) << '\n';
}
}