6814 Tetrahedron
用任何方法,只要计算出 1 h 2 = 1 a 2 + 1 b 2 + 1 c 2 \frac{1}{h^2}=\frac{1}{a^2}+\frac{1}{b^2}+\frac{1}{c^2} h21=a21+b21+c21即可
#include<cstdio>
using namespace std;
typedef long long ll;
const ll p = 998244353;
const ll maxn = 6e6;
int T;
ll n, Inv[maxn + 1], a[maxn + 1];
ll ksm(ll a, ll b) {
ll res = 1;
while (b){
if (b & 1)res = (res * a) % p;
a = (a * a) % p;
b >>= 1;
}
return res;
}
ll inv(ll x) { return ksm(x, p - 2); }
void init() {
for (ll i = 1; i <= maxn; i++)
Inv[i] = inv(i);
for (int i = 1; i <= maxn; i++)
a[i] = (a[i - 1] + (Inv[i] * Inv[i]) % p) % p;
}
int main(void) {
init();
scanf("%d", &T);
while (T--) {
scanf("%lld", &n);
printf("%lld\n", a[n] * Inv[n] % p * 3 % p);
}
return 0;
}
6816 Boring Game
模拟如图所示的过程,将每次折叠重新一次次打开来
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxp = 2 * 200 * (1 << 10) + 5;
int T, n, k, p[maxp];
vector<int>a[maxp];
int main(void) {
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &k);
int len = 2 * n * (1 << k);
int m = 1 << k;
for (int i = 1; i <= m; i++)a[i].clear();
for (int i = 1; i <= len; i++) {
scanf("%d", &p[i]);
a[m].push_back(p[i]);
}
reverse(a[m].begin(), a[m].end());
for (int t = 0; t < k; t++)
for (int i = m - (1 << t) + 1, j = i - 1; i <= m; i++, j--) {
int size = (int)(a[i].size()) / 2;
while (size--) {
a[j].push_back(a[i].back());
a[i].pop_back();
}
}
int dep = a[m].size();
for (int d = 1; d <= dep; d++) {
for (int i = 1; i <= m; i++) {
printf("%d", a[i].back()); a[i].pop_back();
if (d == dep && i == m && a[i].size() == 0)printf("\n");
else printf(" ");
}
}
}
return 0;
}
6822 Paperfolding
折叠完后,在纸的中心画个点,然后按折叠的方式来把纸摊开,最后恢复成开始的样子,看纸面上的点,横竖相连成网格,则划分的区域即为答案。显然左右和上下是等效的,则只看左和上即可,左折x次,横向展开后有2^x个点,上折n-x次,竖向有2^(n-x)个点,然后画画图,可看出n次操作取x个为左折,剩下为上折,答案为(2^x-1)*(2^(n-x)-1)+2*(2^x-1)+2*(2^(n-x)-1)+4(x=0,1,…,n),记得乘以组合数,最后除以2^n
推推公式即可得出答案为2^n+1+2*(3/2)^n
#include<cstdio>
using namespace std;
typedef long long ll;
const ll p = 998244353;
int T;
ll n;
ll ksm(ll a, ll b) {
ll res = 1;
while (b){
if (b & 1)res = (res * a) % p;
a = (a * a) % p;
b >>= 1;
}
return res;
}
ll inv(ll x) { return ksm(x, p - 2); }
int main(void) {
scanf("%d", &T);
while (T--) {
scanf("%lld", &n);
printf("%lld\n", (ksm(2, n) + 1 + 2 * ksm(3LL * inv(2) % p, n)) % p);
}
return 0;
}
6825 Set1
看下题解就懂,但是答案要再除以((2*i-n-1)/2)!,因为取2取2…的操作,其实每次取出来应该有固定位置,因为操作1取的是当前的最小值,取出x,y时,x为操作1取值然后再取y,则必有x<y,也必有在特定的位置才能取到x值。
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn = 5e6;
const ll p = 998244353;
int T, n;
ll f[maxn + 1], pow2[maxn + 1], inv[maxn + 1], cnt[maxn + 1];
ll ksm(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1)res = (res * a) % p;
a = a * a % p;
b >>= 1;
}
return res % p;
}
ll Inv(ll x) {
return ksm(x, p - 2);
}
ll Cmn(ll m, ll n) {//m取n
if (n == 0)return 1;
return f[m] * inv[m - n] % p * inv[n] % p;
}
int main(void) {
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
f[0] = f[1] = pow2[0] = 1; pow2[1] = 2;
for (int i = 2; i <= maxn; i++) {
f[i] = i * f[i - 1] % p;
pow2[i] = pow2[i - 1] * 2 % p;
}
inv[0] = inv[1] = 1; inv[maxn - 1] = Inv(f[maxn - 1]);
for (int i = maxn - 2; i > 1; i--) {
inv[i] = (i + 1) * inv[i + 1] % p;
}
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
int len = (n - 1) / 2;
for (int i = 1; i <= len; i++)cnt[i] = 0;
for (int i = len + 1; i <= n; i++)
cnt[i] = Cmn(i - 1, n - i) * f[n - i] % p * f[2 * i - n - 1] % p * Inv(pow2[(2 * i - n - 1) / 2]) % p * Inv(f[(2 * i - n - 1) / 2]) % p;
ll sum = 0;
for (int i = 1; i <= n; i++)
sum = (sum + cnt[i]) % p;
ll invSum = Inv(sum);
for (int i = 1; i <= n; i++) {
printf("%lld%c", cnt[i] * invSum % p, i == n ? '\n' : ' ');
}
}
return 0;
}