排列问题
比较明显的贪心吧,就先让排名最小的增加到排名第二的权值,再让排名第二的权值增加到排名第三的权值,sort完之后按顺序搞就好了,模数搞错弄了半天。。。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
const LL mod = 998244353;
const int P = 10200001;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
int sta[200001];
int a[200001], b[200001];
int jc[P];
int pow_mod(int a, int k) {
int ans = 1;
while(k) {
if(k & 1) ans = (LL)ans * a % mod;
a = (LL)a * a % mod; k /= 2;
} return ans;
}
int main() {
int tt = read();
jc[0] = 1; for(int i = 1; i < P; i++) jc[i] = (LL)jc[i - 1] * i % mod;
while(tt--) {
int n = read(), m = read(), L = read(), R = read();
int gg = n + m;
int u1 = 0, u2 = 0;
for(int i = 1; i <= n; i++) {
int x = read();
if(x >= L && x <= R) a[++u1] = x;
else b[++u2] = x;
} sort(a + 1, a + u1 + 1), sort(b + 1, b + u2 + 1);
int ans = 1; int l = 1;
for(int i = 2; i <= u2; i++) {
if(b[i] != b[i - 1]) {
ans = (LL)ans * jc[i - l] % mod;
l = i;
}
} ans = (LL)ans * jc[u2 - l + 1] % mod;
int tp = 0, mx = 0; l = 1;
for(int i = 2; i <= u1; i++) {
if(a[i] != a[i - 1]) sta[++tp] = i - l, mx = _max(mx, i - l), l = i;
} sta[++tp] = u1 - l + 1, mx = _max(mx, u1 - l + 1);
sort(sta + 1, sta + tp + 1);
LL s = 0;
for(int i = 1; i <= tp; i++) s += mx - sta[i];
s += (LL)mx * (R - L + 1 - tp);
if(s <= m) {
m -= s;
int z = m % (R - L + 1), k = m / (R - L + 1);
ans = (LL)ans * pow_mod(jc[mx + k + 1], z) % mod;
ans = (LL)ans * pow_mod(jc[mx + k], R - L + 1 - z) % mod;
} else {
int lst = 0, o = R - L + 1 - tp;
for(int i = 1; i <= tp; i++) {
if(lst != sta[i]) {
if(m < (LL)o * (sta[i] - lst)) break;
m -= o * (sta[i] - lst);
lst = sta[i];
} o++;
} if(o == 0) {
for(int i = 1; i <= tp; i++) ans = (LL)ans * jc[sta[i]] % mod;
} else {
int z = m % o, k = m / o;
ans = (LL)ans * pow_mod(jc[lst + k + 1], z) % mod;
ans = (LL)ans * pow_mod(jc[lst + k], o - z) % mod;
for(int i = o + 1 - (R - L + 1 - tp); i <= tp; i++) ans = (LL)ans * jc[sta[i]] % mod;
}
} put((LL)jc[gg] * pow_mod(ans, mod - 2) % mod), puts("");
} return 0;
}
游戏
你只用考虑在[l,r]区间内不是[l,r]区间倍数的数,用线筛把这些数给筛出来,然后会有一个式子,假设这样的数有s个∑i=0n−sCnii!s!(n−i−s)!Cn−s−1s−1(i+s)你推一下就会变成∑(n−s)!s(i+s−1)!(i+s)/i!,直接做就好了。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
int h[5001], f[5001][5001];
int main() {
int n = read();
for(int i = 1; i <= n; i++) h[i] = read();
int ans = 0;
for(int r = 1; r <= n; r++) {
f[r][r] = f[r - 1][r] = 1;
int Y = h[r] - h[r - 1], X = 1, now;
bool bk = 0;
for(int l = r - 2; l >= 1; l--) {
int x = r - l, y = h[r] - h[l];
if((LL)Y * x > (LL)y * X) f[l][r] = f[l + 1][r], X = x, Y = y, bk = 0;
else {
if(!bk) bk = 1, f[l][r] = f[l + 1][r] + 1, now = l;
else f[l][r] = _min(f[l][now] + f[now + 1][r], f[l][now + 1] + f[now + 2][r]);
}
}
} for(int l = 1; l <= n; l++) for(int r = l; r <= n; r++) ans ^= f[l][r];
put(ans);
return 0;
}
守卫
emm。。。
首先一个点r可以看到另一个点l,且l<r,当且仅当其中的点与r的斜率都大于l与r之间的斜率。
然后你考虑对于一段区间[l,r],r肯定要放,类似的假设有一段r看不到的区间[x,y]则要么y放,要么y+1放,直接dp转移即可。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
int h[5001], f[5001][5001];
int main() {
int n = read();
for(int i = 1; i <= n; i++) h[i] = read();
int ans = 0;
for(int r = 1; r <= n; r++) {
f[r][r] = f[r - 1][r] = 1;
int Y = h[r] - h[r - 1], X = 1, now;
bool bk = 0;
for(int l = r - 2; l >= 1; l--) {
int x = r - l, y = h[r] - h[l];
if((LL)Y * x > (LL)y * X) f[l][r] = f[l + 1][r], X = x, Y = y, bk = 0;
else {
if(!bk) bk = 1, f[l][r] = f[l + 1][r] + 1, now = l;
else f[l][r] = _min(f[l][now] + f[now + 1][r], f[l][now + 1] + f[now + 2][r]);
}
}
} for(int l = 1; l <= n; l++) for(int r = l; r <= n; r++) ans ^= f[l][r];
put(ans);
return 0;
}