今天也是一条咸鱼ORZ
场上三题:E,J,K
E:Everything Is Generated In Equal Probability
题解:一个长度为n的排列的逆序期望为C(n, 2)/2 ,因为每一对下标的贡献都是1/2.然后设
d
p
[
i
]
dp[i]
dp[i]为长度为
i
i
i的随机排列的culculate函数值,则由题可得
d
p
[
n
]
=
C
(
n
,
2
)
2
+
Σ
i
=
0
n
C
(
n
,
i
)
∗
d
p
[
i
]
dp[n]=\frac{C(n,2)}{2}+\Sigma_{i=0}^nC(n,i)*dp[i]
dp[n]=2C(n,2)+Σi=0nC(n,i)∗dp[i]
由此可以
O
(
n
2
)
O(n^2)
O(n2)推出
d
p
[
n
]
dp[n]
dp[n]。因为一开始从
[
1
,
n
]
[1,n]
[1,n]随机选取长度,所以最终答案为
Σ
d
p
[
i
]
n
\frac{\Sigma dp[i]}{n}
nΣdp[i]。(听说有大佬
O
(
1
)
O(1)
O(1)直接算出答案,%%%)
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 998244353;
const int maxn = 3e3 + 50;
ll qm(ll a, ll b)
{
ll res = 1;
while(b){
if(b&1) res = res*a%mod;
a = a*a%mod;
b >>= 1;
}return res;
}
ll dp[maxn];
ll p[maxn];
ll inv[maxn];
ll bin[maxn];
ll sum[maxn];
int main()
{
dp[0] = dp[1] = 0;
bin[0] = 1;
p[0] = inv[0] = 1;
for(int i = 1; i < maxn; ++i) p[i] = p[i-1]*i%mod, inv[i] = qm(p[i], mod-2), bin[i] = bin[i-1]*2%mod;
for(int i = 2; i < maxn; ++i){
ll res = bin[i-2]*i%mod*(i-1)%mod;
for(int j = 2; j < i; ++j){
res = (res + p[i]*inv[j]%mod*inv[i-j]%mod*dp[j])%mod;
}
res = res*qm(bin[i]-1, mod-2) % mod;
dp[i] = res;
}
sum[0] = 0;
for(int i = 1; i < maxn; ++i) sum[i] = (sum[i-1] + dp[i])%mod;
int n;
while(scanf("%d", &n)!=EOF){
ll ans = sum[n] * qm(n, mod-2) % mod;
ans = (ans + mod)%mod;
printf("%lld\n", ans);
}
}
J: Just Skip The Problem
题解:最好的选择是每一位都问过去,所以答案是n!,因为对1e6+3取模,所以当 n > = 1 e 6 + 3 n>=1e6+3 n>=1e6+3的时候答案为0,递推求阶乘即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e6 + 3;
ll p[mod];
int main()
{
p[0] = 1;
for(ll i = 1; i < mod; ++i) p[i] = p[i-1]*i%mod;
ll n;
while(~scanf("%lld", &n)){
if(n >= mod) printf("0\n");
else printf("%lld\n",p[n]);
}
}
K:Keen On Everything But Triangle
题解:对于一个数组,从最大值开始判断是否可以组成三角形。它的最大值n如果不能组成三角形,意味着数组内值的范围为
[
n
2
,
n
]
[\frac{n}{2},n]
[2n,n]除了它本身之外最多只有一个,所以每检查两个数,当前数值一定减少了超过一半。离散化之后用主席树查询区间比pos小的最大的数来找第k大值。(有点绕,实际上只需要查询区间第k大,代码写丑了。)
代码:
#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)>>1)
using namespace std;
const int maxn = 1e5 + 50;
int sz[maxn*20], lc[maxn*20], rc[maxn*20];
int T[maxn];
int n, m;
ll cc[maxn];
int num;
ll a[maxn];
int tot;
void build(int pre, int &cur, int l, int r, int pos){
if(!cur) {
cur = ++tot;
sz[cur] = lc[cur] = rc[cur] = 0;
}
sz[cur] = sz[pre] + 1;
if(l == r) return;
if(pos <= mid){
rc[cur] = rc[pre];
build(lc[pre], lc[cur], l, mid, pos);
}
else{
lc[cur] = lc[pre];
build(rc[pre], rc[cur], mid+1, r, pos);
}
return;
}
int query(int pre, int cur, int l, int r, int pos, int &tt){//小于pos的数中找最大的,tt为sz
if(pos < l) return -1;
if(sz[cur] - sz[pre] == 0) return -1;//区间内没有数字了
if(l == r) {
tt = sz[cur] - sz[pre];
return l;
}
int ans = -1;
if(pos > mid) ans = query(rc[pre], rc[cur], mid+1, r, pos, tt);
if(ans == -1) return query(lc[pre], lc[cur], l, mid, pos, tt);
}
void init()
{
tot = num = 0;
for(int i = 1; i <= n; ++i){
scanf("%lld\n", &a[i]);
cc[++num] = a[i];
T[i] = 0;
}
sort(cc+1, cc+1+num);
num = unique(cc+1, cc+1+num) - cc - 1;
for(int i = 1; i <= n; ++i) {
int pos = lower_bound(cc+1, cc+1+num, a[i]) - cc;
build(T[i-1], T[i], 1, num, pos);
}
}
void sol()
{
while(m--){
int l, r;
scanf("%d%d", &l, &r);
int p1, p2, p3;
int t1 = 0, t2 = 0, t3 = 0;
p1 = query(T[l-1], T[r], 1, num, num, t1);
p2 = query(T[l-1], T[r], 1, num, p1-1, t2);
p3 = query(T[l-1], T[r], 1, num, p2-1, t3);
int ok = 0;
while(t1 + t2 + t3 >= 3){
//cout<<"p1:"<<p1<<" p2:"<<p2<<" p3:"<<p3<<endl;
if(t1 >= 3){
printf("%lld\n", cc[p1]*3);ok = 1;break;
}
else if(t1 == 2){
printf("%lld\n", 2*cc[p1] + cc[p2]);ok = 1;break;
}
else {//t1 == 1
if(t2 >= 2 && cc[p2]*2 > cc[p1]){//找到答案
printf("%lld\n", 2*cc[p2] + cc[p1]); ok = 1;break;
}
else if(t2 >= 2){//有两个以上但是无法构成
p1 = p2; p2 = p3;
t1 = t2; t2 = t3;
t3 = 0;
p3 = query(T[l-1], T[r], 1, num, p2-1, t3);
continue;
}
else if(t3 > 0){//有第三小
if(cc[p2] + cc[p3] > cc[p1]){
printf("%lld\n", cc[p1] + cc[p2] + cc[p3]);ok = 1;break;
}
p1 = p2; p2 = p3;
t1 = t2; t2 = t3;
t3 = 0;
p3 = query(T[l-1], T[r], 1, num, p2-1, t3);
continue;
}
}
}
if(!ok) printf("-1\n");
}
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF){
init();sol();
}
}
/*
10 1
1 4 4 4 4 8 15 1 1 1
1 10
*/