1001 Tetrahedron
题意
一个直角四面体的三条直角边在\([1,\ n]\)范围内随机,求直角顶点到对面的距离的平方倒数(\(\frac{1}{h^2}\))的期望值。
思路
先通过向量计算得到\(\frac{1}{h^2}=\frac{1}{a^2}+\frac{1}{b^2}+\frac{1}{c^2}\), 于是\(E(\frac{1}{h^2})=3E(\frac{1}{a^2}) \quad,其中a\in[1,n]\) ,推出
注意逆元的预处理方法,\(inv[i] = mod-mod/i \ * \ inv[mod\%i]\)。
代码
#include
#define ll long long
using namespace std;
const int maxn = 6e6 + 7;
const int mod = 998244353;
int T, n;
int ni[maxn], sum[maxn];
void init() {
ni[1] = sum[1] = 1;
for(int i = 2; i < maxn; i++) {
ni[i] = mod - 1LL * mod/i * ni[mod%i] % mod;
sum[i] = sum[i-1] + 1LL * ni[i] * ni[i] % mod;
sum[i] %= mod;
}
}
ll qpow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
freopen("data.in", "r", stdin);
//freopen("data.out", "w", stdout);
init();
cin >> T;
while(T--) {
cin >> n;
cout << 1LL * sum[n] * 3 % mod * qpow(n, mod - 2) % mod << endl;
}
return 0;
}
1003 Boring Game
题意
有n张纸叠在桌面上,将这些纸从左到右折叠k次,一共分层\(2*n*(1<
思路
用数组来模拟,对于每一次折叠,找到折叠的中点,然后将中点上面的一次逆序加到下面的数组中去。
代码
#include
#define ll long long
using namespace std;
const int maxn = 5e5 + 7;
const int mod = 1e9 + 7;
int T, n, k;
vector v[maxn];
void slove(int l, int r) {
int mid = (l + r) / 2, now = mid + 1;
for(int i = mid; i >= l; i--) {
for(int j = v[i].size() - 1; j >= 0; j--) {
v[now].push_back(v[i][j]);
}
now++;
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
freopen("data.in", "r", stdin);
//freopen("data.out", "w", stdout);
cin >> T;
while(T--) {
cin >> n >> k;
int len = 2 * n * (1 << k);
for(int i = 0; i < maxn; i++) v[i].clear();
for(int i = 0; i < len; i++) {
int temp; cin >> temp;
v[i].push_back(temp);
}
int l = 0, r = len - 1;
for(int _ = 0; _ < k; _++) {
slove(l, r);
l += (r - l) / 2 + 1;
}
for(int i = l; i <= r; i++) {
reverse(v[i].begin(), v[i].end());
for(int j = 0; j < v[i].size(); j++) {
cout << v[i][j];
if(i == r && j == v[i].size() - 1) cout << endl;
else cout << ' ';
}
}
}
return 0;
}
1009 Paperfolding
题意
给一张纸,水平对折,竖直对折,一共进行n次(意味着有\(2^n\)种折法),最后将纸剪一个十字,剪出来会分成很多块,求块数的数学期望。
思路
假设水平折叠了x次,竖直折叠了y次,将折叠后的纸展开会发现,剪开的痕迹就是将原纸张竖直方向上剪了\(2^x\)刀,水平方向上剪了\(2^y\)刀,因此总共剪出了\((2^x+1)*(2^y+1)\)个块。
因此期望就是
代码
#include
#define ll long long
using namespace std;
const int maxn = 1e5 + 7;
const int mod = 998244353;
ll T, n;
ll qpow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
freopen("data.in", "r", stdin);
//freopen("data.out", "w", stdout);
ll inv2 = qpow(2, mod - 2);
cin >> T;
while(T--) {
cin >> n;
ll ans = 1 + qpow(2, n % (mod - 1)) + 2 * qpow(3 * inv2, n % (mod - 1));
ans %= mod;
cout << ans << endl;
}
return 0;
}
1012 Set1
题意
一个初始元素为\(\{1,...,n\}\)的集合依次做两个操作,直到只剩一个元素
-
去除集合中最小的元素
-
随机去除一个元素
问每个数字被剩下的期望值
思路
对于第\(i\)个元素,能剩下的条件是他左边的元素个数不少于右边的元素个数,而且右边的元素个数都是被第二种操作去除。
于是对于每一个数留下来的方案数有\(cnt[i]=C_{r}^{l} \ r! \ \frac{(r-l)!}{(2!)^{(r-l)/2} \ \frac{r-l}{2}}\),其中\(l\)为\(i\)左边的数的个数,\(r\)为\(i\)右边的数的个数。
答案就是每一个的方案数\(cnt[i]\)除方案数求和\(sum\)。
代码
#include
#define ll long long
using namespace std;
const int maxn = 5e6 + 7;
const int mod = 998244353;
int T, n;
int cnt[maxn], fac[maxn], inv[maxn], sum;
int qpow(int a, int b) {
int ans = 1;
while(b) {
if(b & 1) ans = (ll)ans * a % mod;
a = (ll)a * a % mod;
b >>= 1;
}
return ans;
}
void init() {
fac[0] = inv[0] = 1;
for(int i = 1; i < maxn; i++) fac[i] = (ll)fac[i - 1] * i % mod;
inv[maxn - 1] = qpow(fac[maxn - 1], mod - 2);
for(int i = maxn - 2; i >= 1; i--) inv[i] = (ll)inv[i + 1] * (i + 1) % mod;
}
ll C(ll n, ll m) {
return (ll)fac[n] * inv[m] % mod * inv[n - m] % mod;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
freopen("data.in", "r", stdin);
//freopen("data.out", "w", stdout);
init();
cin >> T;
while(T--) {
sum = 0;
cin >> n;
for(int i = 1; i <= n; i++) {
int l = i-1, r = n-i;
if(l >= r) {
int res = (ll)C(l, r) * fac[r] % mod;
int temp = qpow(2, (l-r)/2);
temp = qpow(temp, mod - 2);
res = (ll)res * fac[l-r] % mod * temp % mod;
res = (ll)res * inv[(l-r)/2] % mod;
cnt[i] = res;
sum = ((ll)sum + cnt[i]) % mod;
}
else cnt[i] = 0;
}
sum = qpow(sum, mod - 2);
for(int i = 1; i <= n; i++) {
cout << (ll)cnt[i] * sum % mod;
if(i != n) cout << ' ';
}
cout << endl;
}
return 0;
}