「CSP模擬」模擬測試5
平均數
題意是讓求平均值第K小的連續子區間。
發現直接計算無論怎麼優化都是 \(n^2\) 的,然後發現這樣找K個的似乎可以考慮二分答案。
簡單推一下式子。
記 \(sum[i]\) 為字首和,顯然符合條件的區間有:
即
\[sum[j] - j \times mid \leq sum[i] - i\times mid \]預設 \(j < i\),區間為 \([i+1,j]\),所以顯然下標從0開始。
所以問題轉化為一個類似01分數規劃的東西,check的話用樹狀陣列求逆序對,注意處理下標為0。
程式碼寫得有點長,而且沒有卡常所以有點慢。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; const int maxn = 1e5 + 10; const double eps = 1e-8; double sum[maxn]; int w[maxn]; long long n, k; void Add(int i, int val) { for (; i <= 100001; i += (i & (-i))) w[i] += val; } int Ask(int i) { int ans = 0; for (; i; i -= i & (-i)) ans += w[i]; return ans; } struct node { double data; int pos; }tmp[maxn]; bool cmp(node x, node y) { return x.data < y.data; } bool Check(double mid) { long long cnt = 0; tmp[0] = (node) { 0, 0 }; for (int i = 1; i <= n; i++) tmp[i] = (node) { sum[i] - mid * i, i}; sort(tmp, tmp + 1 + n, cmp); for (int i = n; i >= 0; i--) { cnt += Ask(tmp[i].pos + 1); Add(tmp[i].pos + 1, 1); } for (int i = 0; i <= n; i++) Add(i + 1, -1); return cnt >= k; } int main() { freopen("ave.in", "r", stdin); freopen("ave.out", "w", stdout); scanf("%lld %lld", &n, &k); for (int i = 1; i <= n; i++) { scanf("%lf", &sum[i]); sum[i] += sum[i - 1]; } double l = 1.0, r = 1000000000.0, mid; while (r - l > eps) { mid = (l + r) / 2; //cout<<mid<<endl; if (Check(mid)) r = mid; else l = mid; } printf("%.4lf\n", l); return 0; }
塗色遊戲
並不是很會推這個式子...c一波學長題解吧...
設 \(f[i][j]\) 代表第\(i\)列選\(j\)個顏色的方案數,
\(g[i][j]\)代表用任意\(i\)個顏色填\(j\)個塊的方案數,
\(h[i][j]\)代表上一列選\(i\)個顏色這一列選\(j\)個的方案數
\(g[i][j]=g[i-1][j-1] \times (p-i+1)+g[i][j-1] \times i\),就是第二類斯特林數;
\(h[j][k]=\frac{g[k][n]}{C_{p}^{k}} \times \sum_{x=max(q,j,k)}^{min(p, j+k)}C_{j}^{j+k-x}C_{p-j}^{x-j}\)
\(f[i][j]=f[i-1][k] \times h[k][j]\)
發現\(f\)的轉移跟\(i\)無關,再加上\(m\)如此巨大,可以矩陣乘。
其實並不用真正寫一個矩陣快速冪,但我還是無腦套了板子...
另外,注意卡常。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 105;
const int mo = 998244353;
int n, m, p, q;
long long g[maxn][maxn], h[maxn][maxn], c[maxn][maxn];
struct Mat {
long long w[maxn][maxn];
Mat() {
memset(w, 0, sizeof w);
}
void init() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
w[i][j] = (i == j ? 1 : 0);
}
}
}
Mat operator * (const Mat &b) const {
Mat c;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
c.w[i][j] += w[i][k] * b.w[k][j] % mo;
}
c.w[i][j] %= mo;
}
}
return c;
}
};
long long Qpow(long long x, int t) {
long long s = 1;
while (t) {
if (t & 1) s = s * x % mo;
x = x * x % mo;
t >>= 1;
}
return s;
}
Mat Matpow(Mat x, int t) {
Mat s;
s.init();
while (t) {
if (t & 1) s = s * x;
x = x * x;
t >>= 1;
}
return s;
}
int main() {
//freopen("color.in", "r", stdin);
//freopen("color.out", "w", stdout);
cin >> n >> m >> p >> q;
for (int i = 0; i <= p; i++)
c[i][0] = 1;
for (int i = 1; i <= p; i++)
for (int j = 1; j <= i; j++)
c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mo;
g[0][0] = 1, g[1][1] = 1, g[2][1] = 1;
for (int i = 1; i <= p; i++) {
for (int j = 1; j <= n; j++) {
g[i][j] = (g[i - 1][j - 1] * (p - i + 1) % mo + g[i][j - 1] * i % mo) % mo;
}
}
for (register int j = 1; j <= n; j++) {
for (register int k = 1; k <= n; k++) {
long long sum = 0;
for (int x = max(q, max(j, k)); x <= min(p, j + k); x++)
sum = (sum + c[j][j + k - x] * c[p - j][x - j] % mo) % mo;
h[j][k] = g[k][n] * Qpow(c[p][k], mo - 2) % mo * sum % mo;
}
}
Mat base, ans;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
base.w[i][j] = h[i][j];
for (int i = 1; i <= min(p, n); i++) {
ans.w[1][i] = g[i][n];
}
base = Matpow(base, m - 1);
ans = ans * base;
long long sum = 0;
for (int i = 1; i <= min(n, p); i++)
sum = (sum + ans.w[1][i]) % mo;
cout << sum << endl;
return 0;
}
序列
考場上打了1h+的主席樹掛了...
用線段樹套vector水過。
每個節點開一個vector,存下能夠完全覆蓋此節點代表區間的詢問的x值。(注意保證vector有序)
然後考慮每個a[i]的貢獻,從根一直到區間為i的葉子節點,每到一個節點就在該節點的vector裡二分一下,由於一個詢問最多隻會更新一個節點一次,所以貢獻不會算重。
ans[i]記錄a[i]的貢獻。
修改的話直接計算更新即可。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1e5 + 10;
inline int read() {
int s = 0, w = 1;
char c = getchar();
while (c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
while (c >= '0' && c <= '9') s = s * 10 + c - '0', c = getchar();
return s * w;
}
struct tree {
vector<int> qe;
}t[maxn << 2];
#define ls (u << 1)
#define rs (u << 1 | 1)
void Update(int u, int l, int r, int ql, int qr, int val) {
if (ql <= l && r <= qr) {
t[u].qe.push_back(val);
return;
}
int mid = (l + r) >> 1;
if (ql <= mid) Update(ls, l, mid, ql, qr, val);
if (qr > mid) Update(rs, mid + 1, r, ql, qr, val);
return;
}
int Get(int u, int val) {
int ans, flag = 1;
/*for (int i = 0; i < t[u].qe.size(); i++) {
if (t[u].qe[i] > val) {
flag = 0;
ans = i;
break;
}
}
if (flag) ans = t[u].qe.size();*/
int l = 0, r = t[u].qe.size() - 1, mid;
while (l <= r) {
mid = (l + r) >> 1;
if (t[u].qe[mid] > val) r = mid - 1;
else l = mid + 1;
}
//cout << "************" << endl;
//printf("ans = %d l = %d\n", ans, l);
//cout << "************" << endl;
return l;
}
int Ask(int u, int l, int r, int pos, int val) {
if (l == r) {
return Get(u, val);
}
int mid = (l + r) >> 1;
int ans = 0;
ans += Get(u, val);
if (pos <= mid) ans += Ask(ls, l, mid, pos, val);
else ans += Ask(rs, mid + 1, r, pos, val);
return ans;
}
int n, m, q;
int a[maxn];
int aa[maxn];
struct node {
int l, r, x;
}qq[maxn];
bool cmp(node aa, node bb) { return aa.x < bb.x; }
int main() {
freopen("seq.in", "r", stdin);
freopen("seq.out", "w", stdout);
n = read(), m = read(), q = read();
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= m; i++) {
qq[i].l = read(), qq[i].r = read(), qq[i].x = read();
}
sort(qq + 1, qq + 1 + m, cmp);
for (int i = 1; i <= m; i++) {
Update(1, 1, n, qq[i].l, qq[i].r, qq[i].x);
}
int ans = 0;
for (int i = 1; i <= n; i++) {
aa[i] = Ask(1, 1, n, i, a[i]);
ans += aa[i];
}
printf("%d\n", ans);
//for (int i = 1; i <= n; i++)
//cout << aa[i] << endl;
int u, v, pos, val;
while (q--) {
u = read(), v = read();
pos = u ^ ans;
val = v ^ ans;
ans -= aa[pos];
aa[pos] = Ask(1, 1, n, pos, val);
ans += aa[pos];
printf("%d\n", ans);
}
}