多省省选联考全真模拟考试3
http://csp.ac/contest/11
最重要的是对998244353取模
加上这个取模就200了qwq
T1
所有区间第k大和
考虑排序之后从小到大删除,然后对于一个数,他能当第k大当且仅当他在删完后的序列中有一个区间包括他同时也正好包括k个点
然后这个过程可以用一个链表维护删除,暴力去维护包括k个点的区间
注意当前删除序列和实际序列的差别,是计数标准
复杂度是O(nk+nlogn)的,跑了最快
T3
51nod原题...带边权联通分量计数
先考虑每个边的贡献,然后补集转换
考虑对于一条边两边的子树,如果一个区间不包括这个边那么一定在某子树有编号连续的一段
所以我们对于一条边,把一边的子树全部标记,就是这个样子的
--------__-----
每一段都用作为代价求个和就能做完了
但是我们还需要知道怎么快速求这个和以及怎么知道子树标记
裸的线段树合并啊qwq
T2
考场上就看了一眼的题,因为直接想到AC自动机+矩乘,不太可做qwq
第一问建出AC自动机直接搜索就好了,和最短不公共子串一个样
第二问...dp[i][j][S]表示我长度为i,然后走到自动机j号点,然后经过状态为S,并且没有经过那些爆炸点
所以转移直接枚举下一个放什么就好了
然后第一维要是想矩乘的话那不能有三维啊
所以我们要容斥掉第三维qwq怎么容呢
考虑强制硬点走过几个,比如走过一个,我们第二维就到那个点的终止点
然后其中g(S)表示S集合都强制走过一遍方案数
而且我们转移矩阵是G[i][j]表示从i->j号点一步的方案数
如果j是个坏点就设置为0即可
复杂度只有?
完结散花!
code
T1:
//好像有点难写?
//From Dawn light
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::sort;
#define ll long long
const int P = 998244353;
const int MAXN = 3e6 + 7;
int n, k;
ll ans;
int nxt[MAXN], pre[MAXN];
int a[MAXN];
struct rec {
int a, pos;
bool operator<(const rec &x)const {
return a < x.a;
}
} b[MAXN];
namespace fastIO {
#define BUF_SIZE (1<<19)
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
inline char nc() {
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
}
return *p1++;
}
inline int read() {
int x = 0, f = 1;
char s = nc();
for(; !isdigit(s); s = nc())if(s == '-')f = -1;
for(; isdigit(s); s = nc())x = (x << 1) + (x << 3) + s - '0';
return x * f;
}
}
using namespace fastIO;
inline void init() {
for(int i = 1; i <= n; ++i) {
nxt[i] = i + 1;
pre[i] = i - 1;
}
sort(b + 1, b + n + 1);
//qwq
}
inline void del(int x) {
pre[nxt[x]] = pre[x];
nxt[pre[x]] = nxt[x];
}
inline void chuli(int u, int l, int r) {//尺取即可
for(; l != nxt[u]; l = nxt[l], r = nxt[r]) {
if(r == n + 1)break;
ans = (ans + 1ll * (nxt[r] - r) * (l - pre[l]) % P * a[u] % P) % P;
}
return ;
}
inline void solve() {
for(int i = 1; i <= n; ++i) {
int u = b[i].pos;
int l = u, r = u;
int cnt = 0;
for(cnt = 2; cnt <= k ; ++cnt) {
// printf("%d %d?\n", l, pre[l]);
if(pre[l] != 0)l = pre[l];
else break;
}
for(; cnt <= k; ++cnt) {
if(nxt[r] != n + 1)r = nxt[r];
else break;
}
// printf("%d %d %d? ", cnt, l, r);
if(cnt > k)chuli(u, l, r);
// printf("%d! \n", ans);
del(u);
}
// printf("%lld\n", ans);
return;
}
inline void solve2() {
for(int i = n; i >= 1; --i) {
int u = b[i].pos;
int l = u, r = u;
int cnt = 0;
for(cnt = 2; cnt <= k ; ++cnt) {
// printf("%d %d?\n", l, pre[l]);
if(pre[l] != 0)l = pre[l];
else break;
}
for(; cnt <= k; ++cnt) {
if(nxt[r] != n + 1)r = nxt[r];
else break;
}
// printf("%d %d %d? ", cnt, l, r);
if(cnt > k)chuli(u, l, r);
// printf("%d! \n", ans);
del(u);
}
}
int main() {
// freopen("test.in", "r", stdin);
// freopen("T1.out", "w", stdout);
n = read();
k = read();
for(int i = 1; i <= n; ++i) {
// scanf("%d", &a[i]);
a[i] = read();
b[i].a = a[i];
b[i].pos = i;
}
init();
solve();
init();
solve2();
// ans = ((ans % P + P) % P);
printf("%lld\n", ans);
return 0;
}
T3
#pragma GCC optimize(2)
#pragma G++ optimize(2)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
#define CT const int&
const int MAXN = 2e5 + 7;
const int P = 998244353;
namespace fastIO {
#define BUF_SIZE (1<<19)
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
inline char nc() {
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
}
return *p1++;
}
inline int read() {
int x = 0, f = 1;
char s = nc();
for(; !isdigit(s); s = nc())if(s == '-')f = -1;
for(; isdigit(s); s = nc())x = (x << 1) + (x << 3) + s - '0';
return x * f;
}
}
using namespace fastIO;
int ccnt, n;
int home[MAXN], nxt[MAXN], to[MAXN], len[MAXN], dis[MAXN];
inline void ct(CT x, CT y, CT z) {
ccnt++;
nxt[ccnt] = home[x];
home[x] = ccnt;
to[ccnt] = y;
len[ccnt] = z;
}
ll SUM, ans;
struct rec {
int l1, r1, l2, r2;
//记录0/1
ll s;
rec(): l1(0), r1(0), l2(0), r2(0), s(0) {}
} tr[MAXN << 4];
namespace seg {
#define mid ((x+y)>>1)
int ls[MAXN << 4], rs[MAXN << 4], root[MAXN << 4], T;
inline ll getval(ll x) {
return x * (x + 1) / 2;//不会爆
}
inline rec pushup(rec x, rec y, int lenl, int lenr) { //恶心...
rec nw;
// printf("lson %d %d %d %d %d rson %d %d %d %d %d merge \n", x.s, x.l1, x.r1, x.l2, x.r2, y.s, y.l1, y.r1, y.l2, y.r2);
nw.s = x.s + y.s;
nw.l1 = x.l1;
nw.l2 = x.l2;
nw.r1 = y.r1;
nw.r2 = y.r2;
if(x.r1 && y.l1) {
nw.s -= getval(y.l1) + getval(x.r1);
nw.s += getval(x.r1 + y.l1);
}
if(y.l2 && x.r2) {
nw.s -= getval(y.l2) + getval(x.r2);
nw.s += getval(x.r2 + y.l2);
}
if(x.l1 == lenl) {
// puts("QWQ");
nw.l1 += y.l1;
}
if(x.l2 == lenl) {
nw.l2 += y.l2;
}
if(y.r1 == lenr) {
nw.r1 += x.r1;
}
if(y.r2 == lenr) {
nw.r2 += x.r2;
}
// printf("is %d %d %d %d %d\n", nw.s, nw.l1, nw.r1, nw.l2, nw.r2);
return nw;
}
inline void modify(int &k, int x, int y, int pos) {
if(!k)k = ++T;
if(x == y) {
tr[k].l1 = tr[k].r1 = 1;
tr[k].r2 = tr[k].l2 = 0;
tr[k].s = 1;
return ;
}
if(pos <= mid)modify(ls[k], x, mid, pos);
else modify(rs[k], mid + 1, y, pos);
//单独处理
if(!ls[k]) {
ls[k] = ++T;
tr[T].l2 = tr[T].r2 = mid - x + 1;
tr[T].s = getval(mid - x + 1);
}
if(!rs[k]) {
rs[k] = ++T;
tr[T].l2 = tr[T].r2 = y - mid;
tr[T].s = getval(y - mid);
}
// printf("%d %d %d %d :\n", k, x, y, pos);
tr[k] = pushup(tr[ls[k]], tr[rs[k]], mid - x + 1, y - mid);
}
#undef mid
#define mid ((l+r)>>1)
//...
inline int merge(int x, int y, int l, int r) {
if(!x || !y)return x + y;
if(tr[x].l2 == r - l + 1)return y;
if(tr[y].l2 == r - l + 1)return x;
// printf("%d %d %d %d %d\n", x, y, l, r, mid);
ls[x] = merge(ls[x], ls[y], l, mid);
rs[x] = merge(rs[x], rs[y], mid + 1, r);
if(!ls[x]) {
ls[x] = ++T;
tr[T].l2 = tr[T].r2 = mid - l + 1;
tr[T].s = getval(mid - l + 1);
}
if(!rs[x]) {
rs[x] = ++T;
tr[T].l2 = tr[T].r2 = r - mid;
tr[T].s = getval(r - mid);
}
tr[x] = pushup(tr[ls[x]], tr[rs[x]], mid - l + 1, r - mid);
return x;
}
}
inline void dfs(int u, int F) {
// printf("%d %d?\n", u, F);
for(int i = home[u]; i; i = nxt[i]) {
int v = to[i];
if(v != F) {
dis[v] = len[i];//每个点考虑父亲的边
dfs(v, u);
// printf("?????%d %d? ", u, v);
seg::root[u] = seg::merge(seg::root[u], seg::root[v], 1, n); //线段树合并
// printf("???%d\n", seg::root[u]);
}
}
seg::modify(seg::root[u], 1, n, u);
// printf("%d %d %lld!\n", u, seg::root[u], tr[seg::root[u]].s);
ans = (ans + (((SUM - tr[seg::root[u]].s) % P + P) % P) * dis[u] % P) % P;
}
int main() {
// freopen("test.in", "r", stdin);
// freopen("T3.out", "w", stdout);
n = read();
for(int i = 1, x, y, z; i < n; ++i) {
x = read();
y = read();
z = read();
// printf("%d %d %d*\n", x, y, z);
ct(x, y, z);
ct(y, x, z);
}
SUM = 1ll * n * (n + 1) / 2;
dfs(1, 0);
printf("%lld\n", ans);
return 0;
}