咕了整整一天才来写 2333

这次邓老师没来 /kk,不过打的还算不错,可惜还是有一题没调出来,不然就是 11 题队了 /ll

1001

题意好像有点奇怪,不过 djq 还是一眼看对了,拿了这题一血。

题解

看对题就没啥好说的了,裸签到题,把点按权值从大到小排序,不断加入点,用并查集维护当前连通块个数,乘一下相邻两个权值的差加起来即可。复杂度 O(nlog⁡n)O(n \log n)O(nlogn)。

code by djq

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (int)(n); i ++)
#define rep1(i, n) for(int i = 1; i <= (int)(n); i ++)
#define MP make_pairusing namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MOD = 998244353;int n, m, b[100005];
PII ver[100005];
int rt[100005];int root(int x)
{if(rt[x] == x) return x;return rt[x] = root(rt[x]);
}bool unite(int u, int v)
{u = root(u); v = root(v);if(u == v) return false;rt[v] = u;return true;
}vector<int> G[100005];void solve()
{scanf("%d%d", &n, &m);rep1(i, n) scanf("%d", &b[i]);rep1(i, n) ver[i] = MP(b[i], i);sort(ver + 1, ver + 1 + n);reverse(ver + 1, ver + 1 + n);ver[n + 1].first = 0;rep1(i, n) G[i].clear();rep(i, m) {int u, v;scanf("%d%d", &u, &v);G[u].push_back(v);G[v].push_back(u);}rep1(i, n) rt[i] = i;int cnt = 0;LL ans = 0;rep1(i, n) {cnt ++;int v = ver[i].second;rep(j, G[v].size()) {int u = G[v][j];if(b[u] >= b[v] && unite(u, v)) cnt --;}ans += 1LL * (ver[i].first - ver[i + 1].first) * cnt;}printf("%lld\n", ans);
}int main()
{int T;scanf("%d", &T);while(T --) solve();return 0;
}

1002

其实应该也算个比较套路的题?

考虑拆掉绝对值之后每个点的贡献是 -2,0,2,如果在首尾的话比较特别,是 -1 或 1.

由于 aia_iai​ 互不相同,大概按照十三练里波浪那题 dp 就差不多了。

f(i,j,0/1/2,k)f(i,j,0/1/2,k)f(i,j,0/1/2,k) 表示当前从小到大加到了第 iii 个数,有 jjj 个连续段,其中首尾放了 0/1/2 个数时的第 kkk 大。

转移的话就枚举当前的几种情况:产生新的段;在原来段的开头或结尾加入一个(即不改变段数);合并两段。以及还要考虑当前数字是否放在开头/结尾。

合并前 kkk 大,大概写个类似归并的东西就可以了。复杂度 O(n2k)O(n^2k)O(n2k)。

(转移还是稍微有些复杂的)

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;const int MAXN = 605, MOD = 1e9 + 7;
struct Data { int v, c; } f[2][MAXN][3][25];
int T, n, K, aa[MAXN], len[2][MAXN][3];
void calc(Data *a, const Data *b, int &na, int nb, int val, LL coef) {if (nb == 0) return;if (na == 0) {na = nb;for (int i = 1; i <= na; i++)a[i] = Data { b[i].v + val, b[i].c * coef % MOD };return;}static Data d[25];int i = 1, j = 1, c = 0;while (c < K && (i <= na || j <= nb)) {if (j > nb || (i <= na && a[i].v > b[j].v + val))d[++c] = a[i], ++i;else if (i > na || (j <= nb && b[j].v + val > a[i].v))d[++c] = Data { b[j].v + val, b[j].c * coef % MOD }, ++j;else d[++c] = Data { a[i].v, (a[i].c + b[j].c * coef) % MOD }, ++i, ++j;}for (int i = 1; i <= c; i++) {a[i] = d[i];if (i < c && d[i].v == d[i + 1].v) {puts("fuck");}}na = c;
}int main() {for (scanf("%d", &T); T--;) {scanf("%d%d", &n, &K);for (int i = 1; i <= n; i++)scanf("%d", aa + i);sort(aa + 1, aa + 1 + n);memset(len, 0, sizeof(len));f[0][0][0][1] = Data { 0, 1 };len[0][0][0] = 1;for (int i = 1; i <= n; i++) {int a = i & 1, b = !a;memset(len[a], 0, sizeof(len[a]));for (int j = 1; j <= i; j++) {calc(f[a][j][0], f[b][j - 1][0], len[a][j][0], len[b][j - 1][0], -2 * aa[i], j);calc(f[a][j][0], f[b][j][0], len[a][j][0], len[b][j][0], 0, 2 * j);calc(f[a][j][0], f[b][j + 1][0], len[a][j][0], len[b][j + 1][0], 2 * aa[i], j);calc(f[a][j][1], f[b][j - 1][1], len[a][j][1], len[b][j - 1][1], -2 * aa[i], j - 1);calc(f[a][j][1], f[b][j][1], len[a][j][1], len[b][j][1], 0, 2 * j - 1);calc(f[a][j][1], f[b][j + 1][1], len[a][j][1], len[b][j + 1][1], 2 * aa[i], j);calc(f[a][j][1], f[b][j - 1][0], len[a][j][1], len[b][j - 1][0], -aa[i], 2);calc(f[a][j][1], f[b][j][0], len[a][j][1], len[b][j][0], aa[i], 2);calc(f[a][j][2], f[b][j - 1][2], len[a][j][2], len[b][j - 1][2], -2 * aa[i], j - 2);calc(f[a][j][2], f[b][j][2], len[a][j][2], len[b][j][2], 0, 2 * j - 2);calc(f[a][j][2], f[b][j + 1][2], len[a][j][2], len[b][j + 1][2], 2 * aa[i], j);calc(f[a][j][2], f[b][j - 1][1], len[a][j][2], len[b][j - 1][1], -aa[i], 1);calc(f[a][j][2], f[b][j][1], len[a][j][2], len[b][j][1], aa[i], 1);}}for (int i = 1; i <= K; i++) {const Data &d = f[n & 1][1][2][i];if (d.c) printf("%d %d\n", d.v, d.c);else puts("-1");}}return 0;
}

1003

这场比赛里最神的一道题了吧,好像很多人都觉得 qnlog⁡nq\sqrt{n \log n}qnlogn​ 能过然而被卡了 2333.

神仙随机化题,考虑随机 kkk 个 [0,1][0,1][0,1] 中的实数,最小值的期望是 1k+1\frac{1}{k+1}k+11​。于是考虑给每种颜色随机一个权值,然后求链上权值最小值就可以近似的得到颜色个数。我们多随机几次,取这些最小值的平均值进行比较即可。

于是可以直接树剖维护(倍增空间大预处理复杂度大过不了 qwq),也可以全局平衡二叉树维护(不过好像这题不是查询到根的链,可能难写一些)。

懒得写了,直接贴个题解代码吧。

#include<cstdio>
#include<algorithm>
#pragma GCC optimize(2)
using namespace std;
typedef unsigned int U;
typedef long long ll;
const int N=500010,K=30;
const U inf=~0U;
int Case,n,m,i,j,last,op,x,y,A,B,C,D,col[N],g[N],v[N<<1],nxt[N<<1],ed;
int f[N],d[N],size[N],son[N],top[N],loc[N],q[N],dfn;
U w[N][K],val[1111111][K],tmp[K];
U SX=335634763,SY=873658265,SZ=192849106,SW=746126501;
inline U xorshift128(){U t=SX^(SX<<11);SX=SY;SY=SZ;SZ=SW;return SW=SW^(SW>>19)^t^(t>>8);
}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs1(int x,int y){f[x]=y,d[x]=d[y]+1,size[x]=1;for(int i=g[x];i;i=nxt[i]){int u=v[i];if(u==y)continue;dfs1(u,x);size[x]+=size[u];if(size[u]>size[son[x]])son[x]=u;}
}
void dfs2(int x,int y){q[loc[x]=++dfn]=x;top[x]=y;if(son[x])dfs2(son[x],y);for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]&&v[i]!=son[x])dfs2(v[i],v[i]);
}
inline void up(int x){for(int i=0;i<K;i++)val[x][i]=min(val[x<<1][i],val[x<<1|1][i]);}
void build(int x,int a,int b){if(a==b){int o=col[q[a]];for(int i=0;i<K;i++)val[x][i]=w[o][i];return;}int mid=(a+b)>>1;build(x<<1,a,mid),build(x<<1|1,mid+1,b);up(x);
}
void change(int x,int a,int b,int c,int p){if(a==b){for(int i=0;i<K;i++)val[x][i]=w[p][i];return;}int mid=(a+b)>>1;if(c<=mid)change(x<<1,a,mid,c,p);else change(x<<1|1,mid+1,b,c,p);up(x);
}
inline void umin(U&a,U b){a>b?(a=b):0;}
void ask(int x,int a,int b,int c,int d){if(c<=a&&b<=d){for(int i=0;i<K;i++)umin(tmp[i],val[x][i]);return;}int mid=(a+b)>>1;if(c<=mid)ask(x<<1,a,mid,c,d);if(d>mid)ask(x<<1|1,mid+1,b,c,d);
}
inline ll estimate(int x,int y){for(int i=0;i<K;i++)tmp[i]=inf;for(;top[x]!=top[y];x=f[top[x]]){if(d[top[x]]<d[top[y]])swap(x,y);ask(1,1,n,loc[top[x]],loc[x]);}if(d[x]<d[y])swap(x,y);ask(1,1,n,loc[y],loc[x]);ll ret=0;for(int i=0;i<K;i++)ret+=tmp[i];return ret;
}
int main(){for(i=1;i<N;i++)for(j=0;j<K;j++)w[i][j]=xorshift128();scanf("%d",&Case);while(Case--){scanf("%d%d",&n,&m);for(ed=dfn=last=i=0;i<=n;i++)g[i]=f[i]=d[i]=size[i]=son[i]=0;for(i=1;i<=n;i++)scanf("%d",&col[i]);for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);dfs1(1,0);dfs2(1,1);build(1,1,n);while(m--){scanf("%d%d%d",&op,&A,&B);A^=last,B^=last;if(op==1)change(1,1,n,loc[A],B);else{scanf("%d%d",&C,&D);C^=last,D^=last;ll E=estimate(A,B),F=estimate(C,D);if(E<F){puts("Yes");last++;}else puts("No");}}}
}

1004

本来以为 O(n3)O(n^3)O(n3) 能过的,后来为了求稳还是写了发主席树……

考虑当前限制了 x1,y1,x2,y2x_1,y_1,x_2,y_2x1​,y1​,x2​,y2​ 这个矩形,那么最终的路径要么经过 (x1−1,y2+1)(x_1-1,y2+1)(x1​−1,y2+1) 这个格子或其上面的某个鸽子,要么经过 (x2+1,y1−1)(x2+1,y1-1)(x2+1,y1−1) 或其左边的某个格子。

注意到权值定义为 (n2)ai,j(n^2)^{a_{i,j}}(n2)ai,j​,也就是说能选大的就尽量选大的。我们考虑 dp,f(i,j)f(i,j)f(i,j) 表示 (1,1)(1,1)(1,1) 到 (i,j)(i,j)(i,j) 能得到的最大值,g(i,j)g(i,j)g(i,j) 表示 (i,j)(i,j)(i,j) 到 (n,n)(n,n)(n,n) 的最大值,于是现在的问题就落到了比较上。

我们用可持久化线段树维护每种数字的出现次数,比较大小的话就直接线段树二分,每个节点维护下面次数的 hash 值和答案(刚好答案也可以作为第二种 hash)。

接下来要算一下对于 (x,y)(x,y)(x,y),强制经过其上方的格子能获得的最大值。首先要么是 (x−1,y)(x-1,y)(x−1,y) 的答案,要么是强制经过 (x,y)(x,y)(x,y) 的答案。这个时候我们发现需要比较两个主席树加起来,和另外两个主席树加起来的大小(因为要把 f(x,y)+g(x,y)f(x,y)+g(x,y)f(x,y)+g(x,y) 作为 (x,y)(x,y)(x,y) 的权值)。hash 只要是正常的字符串 hash,就可以直接加,因此还是可以线段树二分的。复杂度 O(n2log⁡n+qlog⁡n)O(n^2 \log n + q \log n)O(n2logn+qlogn)。

自己写的代码找不到了,下面是 code by djq。

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (int)(n); i ++)
#define rep1(i, n) for(int i = 1; i <= (int)(n); i ++)
#define MP make_pairusing namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int D0 = 243, D1;
int MOD0 = 998244353, MOD1 = 1e9 + 7;
int PW0[200005], PW1[200005];void init_pw()
{PW0[0] = PW1[0] = 1;rep1(i, 200000) {PW0[i] = 1LL * PW0[i - 1] * D0 % MOD0;PW1[i] = 1LL * PW1[i - 1] * D1 % MOD1;}
}namespace segt
{int cnt[8000005], hs0[8000005], hs1[8000005], lson[8000005], rson[8000005], tot;void init(){memset(hs0, 0, sizeof(hs0));memset(hs1, 0, sizeof(hs1));memset(lson, -1, sizeof(lson));memset(rson, -1, sizeof(rson));tot = 0;}void pushup(int cur){hs0[cur] = ((lson[cur] == -1 ? 0 : hs0[lson[cur]]) + (rson[cur] == -1 ? 0 : hs0[rson[cur]])) % MOD0;hs1[cur] = ((lson[cur] == -1 ? 0 : hs1[lson[cur]]) + (rson[cur] == -1 ? 0 : hs1[rson[cur]])) % MOD1;}int modify(int cur, int dat, int cl, int cr){int ret = tot ++;if(cl == cr) {cnt[ret] = (cur == -1 ? 0 : cnt[cur]) + 1;hs0[ret] = 1LL * PW0[dat] * cnt[ret] % MOD0;hs1[ret] = 1LL * PW1[dat] * cnt[ret] % MOD1;return ret;}int mid = cl + cr >> 1;if(dat <= mid) {lson[ret] = modify(cur == -1 ? -1 : lson[cur], dat, cl, mid);rson[ret] = cur == -1 ? -1 : rson[cur];} else {lson[ret] = cur == -1 ? -1 : lson[cur];rson[ret] = modify(cur == -1 ? -1 : rson[cur], dat, mid + 1, cr);}pushup(ret);return ret;}int comp(int a, int b, int cl, int cr){if(a == -1 && b == -1) return 0;if(a == -1) return 1;if(b == -1) return -1;if(hs0[a] == hs0[b] && hs1[a] == hs1[b]) return 0;if(cl == cr) return cnt[a] < cnt[b] ? 1 : -1;int mid = cl + cr >> 1;int ret = comp(rson[a], rson[b], mid + 1, cr);if(ret == 0) ret = comp(lson[a], lson[b], cl, mid);return ret;}int comp2(int a0, int a1, int b0, int b1, int cl, int cr){int ah0 = ((a0 == -1 ? 0 : hs0[a0]) + (a1 == -1 ? 0 : hs0[a1])) % MOD0;int ah1 = ((a0 == -1 ? 0 : hs1[a0]) + (a1 == -1 ? 0 : hs1[a1])) % MOD1;int bh0 = ((b0 == -1 ? 0 : hs0[b0]) + (b1 == -1 ? 0 : hs0[b1])) % MOD0;int bh1 = ((b0 == -1 ? 0 : hs1[b0]) + (b1 == -1 ? 0 : hs1[b1])) % MOD1;if(ah0 == bh0 && ah1 == bh1) return 0;if(cl == cr) return (a0 == -1 ? 0 : cnt[a0]) + (a1 == -1 ? 0 : cnt[a1]) <(b0 == -1 ? 0 : cnt[b0]) + (b1 == -1 ? 0 : cnt[b1]) ? 1 : -1;int mid = cl + cr >> 1;int ret = comp2(a0 == -1 ? -1 : rson[a0], a1 == -1 ? -1 : rson[a1],b0 == -1 ? -1 : rson[b0], b1 == -1 ? -1 : rson[b1], mid + 1, cr);if(ret == 0) ret = comp2(a0 == -1 ? -1 : lson[a0], a1 == -1 ? -1 : lson[a1],b0 == -1 ? -1 : lson[b0], b1 == -1 ? -1 : lson[b1], cl, mid);return ret;}
}int n, q, a[405][405];
int dp0[405][405], f1[405][405], dp1[405][405], lpos[405][405], upos[405][405];void solve()
{scanf("%d%d", &n, &q);rep1(i, n) rep1(j, n) scanf("%d", &a[i][j]);D1 = n * n;init_pw();segt::init();memset(dp0, -1, sizeof(dp0));memset(f1, -1, sizeof(f1));memset(dp1, -1, sizeof(dp1));memset(lpos, 0, sizeof(lpos));memset(upos, 0, sizeof(upos));rep1(i, n) rep1(j, n) {dp0[i][j] = segt::comp(dp0[i - 1][j], dp0[i][j - 1], 0, 262143) == -1 ? dp0[i - 1][j] : dp0[i][j - 1];dp0[i][j] = segt::modify(dp0[i][j], a[i][j], 0, 262143);}for(int i = n; i >= 1; i --) for(int j = n; j >= 1; j --) {f1[i][j] = segt::comp(dp1[i + 1][j], dp1[i][j + 1], 0, 262143) == -1 ? dp1[i + 1][j] : dp1[i][j + 1];dp1[i][j] = segt::modify(f1[i][j], a[i][j], 0, 262143);}rep1(i, n) rep1(j, n) {int lj = lpos[i][j - 1];lpos[i][j] = segt::comp2(dp0[i][lj], f1[i][lj], dp0[i][j], f1[i][j], 0, 262143) == -1 ? lj : j;}rep1(i, n) rep1(j, n) {int ui = upos[i - 1][j];upos[i][j] = segt::comp2(dp0[ui][j], f1[ui][j], dp0[i][j], f1[i][j], 0, 262143) == -1 ? ui : i;}rep(i, q) {int lx, rx, ly, ry;scanf("%d%d%d%d", &lx, &rx, &ly, &ry);int i0 = rx + 1, j0 = ly - 1, i1 = lx - 1, j1 = ry + 1;j0 = lpos[i0][j0];i1 = upos[i1][j1];int ret = segt::comp2(dp0[i0][j0], f1[i0][j0], dp0[i1][j1], f1[i1][j1], 0, 262143) == -1 ?(segt::hs1[dp0[i0][j0]] + segt::hs1[f1[i0][j0]]) % MOD1 : (segt::hs1[dp0[i1][j1]] + segt::hs1[f1[i1][j1]]) % MOD1;printf("%d\n", ret);}
}int main()
{int T;scanf("%d", &T);while(T --) solve();return 0;
}

1005

这个题还是比较 easy 的,考虑对于一个工人,找到他最小值的所在位置扔到一个 vector 里(为了不出错把最小值左右两个整数都加入)。

接下来考虑对于 vector 里的每个元素,找到第一个没有在 set 里出现过的大于它的数字 kkk,把 kkk 扔到 set 里。

同理的,对于 vector 里的每个元素,找到第一个没有在 set 里出现过的小于它的数字 kkk,把 kkk 扔到 set 里。

然后对于 set 里的元素,和工人两两连边,跑 nnn 遍费用流即可。不难发现最优解肯定能够被包含在上面的构造方法中,因此点数 O(n)O(n)O(n),边数 O(n2)O(n^2)O(n2),肯定能过。

code by djq

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (int)(n); i ++)
#define rep1(i, n) for(int i = 1; i <= (int)(n); i ++)
#define MP make_pairusing namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL INF = 1.3e17;namespace flow
{const int MAXN = 400;struct edge{int to, cap;LL cost;};int n, m;edge ed[30005];vector<int> G[405];void clear(){m = 0;rep(i, n) G[i].clear();}void add_edge(int u, int v, int fl, LL co){ed[m].to = v; ed[m].cap = fl; ed[m].cost = co; G[u].push_back(m); m ++;ed[m].to = u; ed[m].cap = 0; ed[m].cost = -co; G[v].push_back(m); m ++;}LL h[405];LL pat[405];int prev[405];bool vis[405];bool dijk(int s, int t){rep(i, n) {pat[i] = INF;vis[i] = false;}pat[s] = 0;priority_queue<pair<LL, int> > que;que.push(MP(0, s));while(!que.empty()) {int cur = que.top().second;que.pop();if(vis[cur]) continue;vis[cur] = true;rep(i, G[cur].size()) {int ce = G[cur][i];if(ed[ce].cap == 0) continue;if(pat[ed[ce].to] > pat[cur] + ed[ce].cost) {pat[ed[ce].to] = pat[cur] + ed[ce].cost;prev[ed[ce].to] = ce;que.push(MP(-pat[ed[ce].to], ed[ce].to));}}}return pat[t] != INF;}void mcf(int s, int t, LL* ret){rep(i, n) h[i] = 0;LL ans = 0;while(dijk(s, t)) {//in this occasion flow must be 1int cur = t, cf = 1;while(cur != s) {ed[prev[cur]].cap -= cf;ed[prev[cur] ^ 1].cap += cf;cur = ed[prev[cur] ^ 1].to;}rep(i, m) ed[i].cost += pat[ed[i ^ 1].to] - pat[ed[i].to];rep(i, n) h[i] += pat[i];ans += h[t] * cf;*(++ ret) = ans;}}
}int n, m;
LL a[55], b[55], c[55];
set<LL> S;
vector<LL> hv, nhv;
LL ans[55];void solve()
{scanf("%d%d", &n, &m);rep(i, n) scanf("%lld%lld%lld", &a[i], &b[i], &c[i]);hv.clear();nhv.clear();rep(i, n) {if(b[i] > 0) hv.push_back(1);else {LL pt = max(min((-b[i]) / 2 / a[i], m - 1LL), 1LL);if(pt >= 1 && pt <= m) hv.push_back(pt);if(pt + 1 >= 1 && pt + 1 <= m) hv.push_back(pt + 1); }}S.clear();rep(i, hv.size()) {int cur = hv[i];while(S.find(cur) != S.end()) cur ++;if(cur < 1 || cur > m) continue;nhv.push_back(cur);S.insert(cur);}S.clear();rep(i, hv.size()) {int cur = hv[i];while(S.find(cur) != S.end()) cur --;if(cur < 1 || cur > m) continue;nhv.push_back(cur);S.insert(cur);}sort(nhv.begin(), nhv.end());nhv.resize(unique(nhv.begin(), nhv.end()) - nhv.begin());flow::n = n + nhv.size() + 2;flow::clear();rep(i, n) flow::add_edge(flow::n - 2, i, 1, 0);rep(i, nhv.size()) flow::add_edge(i + n, flow::n - 1, 1, 0);rep(i, n) rep(j, nhv.size())flow::add_edge(i, j + n, 1, a[i] * nhv[j] * nhv[j] + b[i] * nhv[j] + c[i]);flow::mcf(flow::n - 2, flow::n - 1, ans);rep1(i, n) printf("%lld%c", ans[i], " \n"[i == n]);
}int main()
{int T;scanf("%d", &T);while(T --) solve();return 0;
}

1006

刚开始以为是那个 PA 原题,吓懵了……仔细一看发现原来只需要判断就行。那就是签到题了,随便取几个质数膜一下判相不相等即可。复杂度 O(n)O(n)O(n)。

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
template<typename T> void chkmax(T &a, const T &b) { a = a < b ? b : a; }
template<typename T> void chkmin(T &a, const T &b) { a = a < b ? a : b; }const int MAXN = 2000005, B = 5;
const int MOD[B] = { 1000000007, 1000000009, 1000000021, 1000000033, 1000000087 };
int fib[MAXN][5], arr[B], brr[B], crr[B], T, na, nb, nc;
bool cc[MAXN];
void init() {int n = 2e6 + 3;for (int i = 0; i < B; i++)fib[0][i] = 1, fib[1][i] = 1;for (int i = 2; i <= n; i++)for (int j = 0; j < B; j++)fib[i][j] = (fib[i - 1][j] + fib[i - 2][j]) % MOD[j];
}int main() {init();for (scanf("%d", &T); T--;) {scanf("%d", &na);memset(arr, 0, sizeof(arr));memset(brr, 0, sizeof(brr));memset(crr, 0, sizeof(crr));for (int i = 1; i <= na; i++) {int t; scanf("%d", &t);if (t) for (int j = 0; j < B; j++)arr[j] = (arr[j] + fib[i][j]) % MOD[j];}scanf("%d", &nb);for (int i = 1; i <= nb; i++) {int t; scanf("%d", &t);if (t) for (int j = 0; j < B; j++)brr[j] = (brr[j] + fib[i][j]) % MOD[j];}scanf("%d", &nc);for (int i = 1; i <= nc; i++) {int t; scanf("%d", &t);cc[i] = t;if (t) for (int j = 0; j < B; j++)crr[j] = (crr[j] + fib[i][j]) % MOD[j];}for (int i = 0; i < B; i++)arr[i] = (LL)arr[i] * brr[i] % MOD[i];for (int i = 1; i <= nc; i++) if (!cc[i]) {if (cc[i - 1] || cc[i + 1]) continue;bool flag = true;for (int j = 0; j < B; j++)if ((crr[j] + fib[i][j]) % MOD[j] != arr[j]){ flag = false; break; }if (flag) {printf("%d\n", i);break;}}}return 0;
}

1007

要求直径最小,可以二分答案,然后记 f(i,j)f(i,j)f(i,j) 表示 iii 的子树,有 jjj 条边选了权值 aaa 时 iii 子树的深度最小是多少。转移的话枚举当前儿子选了多少个 aaa,如果当前儿子和之前的儿子形成的路径已经 >mid>mid>mid 了就不能转移。最后看有没有合法方案即可。复杂度 O(nklog⁡1014)O(nk \log 10^{14})O(nklog1014)。

code by lqs

#include<bits/stdc++.h>
using namespace std;
int test,n,k,x,y,a,b;
long long l,r,mid,dp[22222][22],f[22],gg[22],nf[22];
struct edge
{int to,a,b;
};
vector<edge> g[22222];
void dfs(int i,int fa)
{for (int j=0;j<g[i].size();j++){int to=g[i][j].to;if (to==fa) continue;dfs(to,i);}for (int j=0;j<=k;j++) f[j]=1e18;f[0]=0;for (int j=0;j<g[i].size();j++){int to=g[i][j].to;if (to==fa) continue;gg[0]=dp[to][0]+g[i][j].b;for (int h=1;h<=k;h++){gg[h]=min(dp[to][h]+g[i][j].b,dp[to][h-1]+g[i][j].a);}for (int h=0;h<=k;h++) nf[h]=1e18;for (int h=0;h<=k;h++){for (int p=0;p+h<=k;p++){if (f[h]+gg[p]<=mid) nf[h+p]=min(nf[h+p],max(f[h],gg[p]));}}for (int h=0;h<=k;h++) f[h]=nf[h];}for (int j=0;j<=k;j++) dp[i][j]=f[j];
}
bool check()
{dfs(1,0);return (dp[1][k]<=mid);
}
int main()
{scanf("%d",&test);while(test--){scanf("%d%d",&n,&k);for (int i=1;i<=n;i++) g[i].clear();for (int i=1;i<n;i++){scanf("%d%d%d%d",&x,&y,&a,&b);g[x].push_back((edge){y,a,b});g[y].push_back((edge){x,a,b});}l=0;r=1e14;while(l<=r){mid=(l+r)>>1;if (check()) r=mid-1;else l=mid+1;}printf("%lld\n",l);}return 0;
}

1008

假设没有加入删除操作,我们考虑把这些函数按照 aia_iai​ 排序,接下来从左向右扫维护一个栈,假设当前扫到了 iii,如果 iii 和 stack[top]stack[top]stack[top] 的交点在 stack[top]stack[top]stack[top] 和 stack[top−1]stack[top-1]stack[top−1] 的交点的左边,那么 stack[top]stack[top]stack[top] 就可以被删掉了。

查询的话直接二分在哪个函数上即可。

现在有了插入删除操作,我们直接线段树分治。对于每个线段树节点都像上面那样处理;对于一个询问,查询它在线段树上所有祖先的答案取最小值即可。

复杂度 O(nlog⁡2n)O(n \log^2 n)O(nlog2n)。

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
template<typename T> void chkmin(T &a, const T &b) { a = a < b ? a : b; }const int MAXN = 300005;
struct Func {int a; LL b;LL calc(int x) const {LL t = x - a;return t * t * t * t + b;}
} fun[MAXN];int inter(const Func &a, const Func &b) {int l = 0, r = 5e4 + 5;while (l + 1 < r) {int mid = (l + r) >> 1;if (a.calc(mid) < b.calc(mid)) l = mid;else r = mid;}return l;
}int tn, T, n, m, beg[MAXN], ed[MAXN], id[MAXN];
struct Seg { Func f; int x; };
vector<Seg> tr[MAXN];
struct Qry { int t, p; };
vector<Qry> qry;
void update(int a, int b, int d, int l = 1, int r = tn, int k = 1) {if (a > r || b < l) return;if (a <= l && b >= r) {while (!tr[k].empty() && (tr[k].back().f.a == fun[d].a ||tr[k].back().x >= inter(tr[k].back().f, fun[d])))tr[k].pop_back();if (tr[k].empty()) tr[k].push_back(Seg { fun[d], 0 });else tr[k].push_back(Seg { fun[d], inter(tr[k].back().f, fun[d]) });return;}int mid = (l + r) >> 1;update(a, b, d, l, mid, k << 1);update(a, b, d, mid + 1, r, k << 1 | 1);
}LL ask(int k, int x) {LL ans = 9e18;for (k += tn - 1; k > 0; k >>= 1) {int l = 0, r = tr[k].size();if (!r) continue;while (l + 1 < r) {int mid = (l + r) >> 1;if (tr[k][mid].x < x) l = mid;else r = mid;}chkmin(ans, tr[k][l].f.calc(x));}return ans;
}int main() {for (scanf("%d", &T); T--;) {scanf("%d%d", &n, &m);int tim = 1;for (int i = 1; i <= n; i++)scanf("%d%lld", &fun[i].a, &fun[i].b);for (int i = 1; i <= m; i++) {int o, a; LL b; scanf("%d%d", &o, &a);if (o == 1) {scanf("%lld", &b);fun[++n] = Func { a, b };beg[n] = ++tim;} else if (o == 2) {ed[a] = tim++;} else qry.push_back(Qry { tim, a });}for (int i = 1; i <= n; i++) id[i] = i;sort(id + 1, id + 1 + n, [&](int x, int y){ return fun[x].a == fun[y].a ? fun[x].b > fun[y].b : fun[x].a < fun[y].a; });for (tn = 1; tn < tim; tn <<= 1);for (int i = 1; i <= n; i++) {int d = id[i];if (ed[d] == 0) ed[d] = tim;update(beg[d], ed[d], d);}for (const Qry &q : qry) {LL t = ask(q.t, q.p);if (t > 8e18) puts("-1");else printf("%lld\n", t);}qry.clear();for (int i = 1; i <= tn * 2; i++)tr[i].clear();for (int i = 1; i <= n; i++)beg[i] = ed[i] = 0;}return 0;
}

1009

暴力可过题。考虑每种轮廓的外接矩形的面积和不超过 4×1084 \times 10^84×108,直接暴力枚举外接矩形内的所有点,判一下在不在轮廓内即可。判断的话可以看他左边的轮廓线条数是不是奇数,是奇数就在里面,否则就在外面。

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
template<typename T> void chkmax(T &a, const T &b) { a = a < b ? b : a; }
template<typename T> void chkmin(T &a, const T &b) { a = a < b ? a : b; }namespace IO {const int MAXR = 10000000;char _READ_[MAXR], _PRINT_[MAXR];int _READ_POS_, _PRINT_POS_, _READ_LEN_;inline char readc() {#ifndef ONLINE_JUDGEreturn getchar();#endifif (!_READ_POS_) {if (feof(stdin)) return -1;_READ_LEN_ = fread(_READ_, 1, MAXR, stdin);}char c = _READ_[_READ_POS_++];if (_READ_POS_ == _READ_LEN_) _READ_POS_ = 0;return c;}template<typename T> inline int read(T &x) {x = 0; register int flag = 1, c;while (((c = readc()) < '0' || c > '9') && c != '-')if (c < 0) return -1;if (c == '-') flag = -1; else x = c - '0';while ((c = readc()) >= '0' && c <= '9') x = x * 10 - '0' + c;x *= flag; return 0;}inline int read(char *s) {register int len = 0, c;while (isspace(c = readc()) || c <= 0)if (c < 0) return -1;s[len++] = c;while (!isspace(c = readc()) && c) s[len++] = c;s[len] = 0;return len;}template<typename T1, typename ...T2> inline int read(T1 &a, T2&... x) {return read(a) | read(x...);}inline void ioflush() { fwrite(_PRINT_, 1, _PRINT_POS_, stdout), _PRINT_POS_ = 0; fflush(stdout); }inline void printc(char c) {if (!c) return;_PRINT_[_PRINT_POS_++] = c;if (_PRINT_POS_ == MAXR) ioflush();}template<typename T> inline void print(T x, char c = '\n') {if (x < 0) printc('-'), x = -x;if (x) {static char sta[20];register int tp = 0;for (; x; x /= 10) sta[tp++] = x % 10 + '0';while (tp > 0) printc(sta[--tp]);} else printc('0');printc(c);}inline void print(char *s, char c = '\n') {for (int i = 0; s[i]; i++) printc(s[i]);printc(c);}inline void print(const char *s, char c = '\n') {for (int i = 0; s[i]; i++) printc(s[i]);printc(c);}template<typename T1, typename ...T2> inline void print(T1 x, T2... y) {print(x, ' '), print(y...);}
}const int MAXN = 405, MAXM = 400005;
int mt[MAXN][MAXN], vis[MAXM], n, m, Q, T, tim;
int tag[MAXN][MAXN];
char str[MAXM];int main() {for (IO::read(T); T--;) {IO::read(n, m, Q);for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)IO::read(mt[i][j]);while (Q--) {int x, y; IO::read(x, y);int l = IO::read(str), x1 = n, y1 = m, x2 = 0, y2 = m;for (int i = 0; i < l; i++) {chkmin(x1, x), chkmin(y1, y);chkmax(x2, x), chkmax(y2, y);switch (str[i]) {case 'L': tag[x--][y + 1] ^= 1; break;case 'R': tag[++x][y + 1] ^= 1; break;case 'D': --y; break;case 'U': ++y; break;}}++x1, ++y1;++tim;int ans = 0;for (int i = x1; i <= x2; i++) {int t = 0;for (int j = y1; j <= y2; j++) {t ^= tag[i][j];if (t && vis[mt[i][j]] != tim)vis[mt[i][j]] = tim, ++ans;tag[i][j] = 0;}tag[i][y2 + 1] = 0;}IO::print(ans);}}IO::ioflush();return 0;
}

1010

暴搜题,每种物品至少会选择一个,因此复杂度最坏为 O(3n/3)O(3^{n/3})O(3n/3)。

#include<bits/stdc++.h>
using namespace std;
int test,n,k,a[55],b[55],c[55],d[55];
int cnt[55],id[55][55],sa,sb,sc,sd,t,mx;
long long ans;
void dfs(int i)
{if (i==mx+1){ans=max(ans,1ll*(100+sa)*(100+sb)*(100+sc)*(100+sd));return;}if (!cnt[i]){dfs(i+1);return;}for (int j=1;j<=cnt[i];j++){sa+=a[id[i][j]];sb+=b[id[i][j]];sc+=c[id[i][j]];sd+=d[id[i][j]];dfs(i+1);sa-=a[id[i][j]];sb-=b[id[i][j]];sc-=c[id[i][j]];sd-=d[id[i][j]];}
}
int main()
{scanf("%d",&test);while(test--){scanf("%d%d",&n,&k);memset(cnt,0,sizeof(cnt));mx=0;for (int i=1;i<=n;i++){scanf("%d%d%d%d%d",&t,&a[i],&b[i],&c[i],&d[i]);mx=max(mx,t);cnt[t]++;id[t][cnt[t]]=i;}ans=-1e18;sa=sb=sc=sd=0;dfs(1);printf("%lld\n",ans);}return 0;
}

1011

这个题和第一场冲了……导致一个 hard 变成了 medium-easy。考虑令一个物品的两种权值为 ai+bi,aia_i+b_i,a_iai​+bi​,ai​,就转化成了这一题的第一部分。代码就不放第二次了。

1012

刚开始看成了字符串的编辑距离,写了半天发现没过样例……才发现这题水的不行。

f(i,j,k)f(i,j,k)f(i,j,k) 表示最大的 xxx 使得 A[x...i]A[x...i]A[x...i] 和 B[1...j]B[1...j]B[1...j] 的 LCS 长度至少为 kkk。直接 O(n2)O(n^2)O(n2) 转移即可,询问的话找到最大的 kkk 使得 f(r,m,k)≥lf(r,m,k) \ge lf(r,m,k)≥l 即可。复杂度 O(nm2)O(nm^2)O(nm2)。

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
template<typename T> void chkmax(T &a, const T &b) { a = a < b ? b : a; }
template<typename T> void chkmin(T &a, const T &b) { a = a < b ? a : b; }const int MAXN = 100005;
int f[MAXN][25][25], n, m, Q, T;
char A[MAXN], B[25];int main() {for (scanf("%d", &T); T--;) {scanf("%s%s", A + 1, B + 1);n = strlen(A + 1), m = strlen(B + 1);f[0][0][0] = 1;for (int i = 1; i <= n; i++) {f[i][0][0] = i + 1;for (int j = 1; j <= m; j++) {f[i][j][0] = i + 1;if (A[i] == B[j]) for (int k = 1; k <= m; k++)f[i][j][k] = f[i - 1][j - 1][k - 1];else for (int k = 1; k <= m; k++)f[i][j][k] = max(f[i - 1][j][k], f[i][j - 1][k]);}}scanf("%d", &Q);while (Q--) {int l, r; scanf("%d%d", &l, &r);int ans = 0;for (int k = 1; k <= m; k++)if (f[r][m][k] >= l) chkmax(ans, k);else break;printf("%d\n", r - l + 1 + m - 2 * ans);}}return 0;
}

HDU 2020 多校第二场 游记相关推荐

  1. Fake Maxpooling(2020多校第二场F)

    Fake Maxpooling(2020多校第二场F) 文章目录 题意: 题解: 代码: 题意: 一个n * m的矩阵,第i行第j列的值是lcm(i,j),然后给定一个 k * k的子矩阵(k< ...

  2. Duration(2020多校第二场D)

    Duration(2020多校第二场D) 文章目录 题意 题解 代码 首先,非常感谢出题人出这个题,避免了我全wa的尴尬 题意 求两个时间相差多少秒,两个时间为同一天 题解 全部转化成秒,然后求差 代 ...

  3. Boundary(2020多校第二场B)

    Boundary(2020多校第二场B) 文章目录 题意: 题解: 思路1: 代码: 思路二 代码 题意: 坐标平面有n个点(不与原点(0,0)重复),现考虑一个圆,(0,0)点在圆的边界,问这个圆的 ...

  4. Cover the Tree(2020多校第二场C)

    Cover the Tree 文章目录 题意: 题解: 代码 题意: 一个无向树,选择最少数量的链子,能将树上所有边覆盖,答案不唯一 (1≤n≤2×105) 链子就是两点之间的边 看看样例 输入 5 ...

  5. 2021牛客暑假多校第二场 K题—Stack (链表)

    2021牛客暑假多校第二场 K题-Stack 题意: 一个单调栈,给你第n次操作时里面数据的数量,让你给出里面塞入的会是哪些数字. 主要思想:链表模拟 (代码里面有注释) (题解一开始说的是拓扑,后来 ...

  6. 牛客多校第二场补题(继续罚坐)

    牛客多校第二场(继续罚坐场) Draw Grids ZYT和LBC玩游戏,在4*4的矩阵中,从起点开始,每个人只能连一条直线,且只能在起点或者上一个人的终点位置连上这个位置相邻的一条直线,并且不能形成 ...

  7. 【多校训练】2021牛客多校第二场

    [前言] 这是打的第二场,rk39,但是AB这两个比较简单的题都没做emm,大概还是磨合的不够.然后感觉对于阈值类的东西还不是很敏感,应该看到不太好做就直接去想这种阈值的.校内3/9(然后就开启了常年 ...

  8. HDU 2020 多校第七场 游记

    又是被 djq 带飞的一场 orz,终场 rk2,又是罚时被锤了 1001,1002 俩 hard 先略过,不会做 /ll 1003 这种数数神题被 djq 一眼秒了,我还能说什么-- 首先我们考虑合 ...

  9. 2020牛客暑假多校第二场补题

    比赛链接:link 题目 A kmp + Hash B 几何 C dfs D 签到题 F 单调区间 + gcd筛 G bitset神奇用法 H 权值线段树(动态开点/离散化) J 群论     A k ...

最新文章

  1. 拥抱开放计算标准 重构数据中心格局
  2. 分享我常用的5个免费的在线 SQL 数据库环境,简直太方便了!
  3. 《易学C++(第2版)》——1.10 习题
  4. python创造订单_Odoo 10根据销售订单创建项目
  5. 怎么判断再一个局域网内一个ip被两台机器占用_交换机与 VLAN 到底是怎么来的...
  6. SpringMVC配置视图的直接映射view-controller命名空间
  7. pip工具使用总结以及常用库PIL、freetype的安装
  8. Delphi中使用全局钩子
  9. oracle查看分区表
  10. Spring.NET教程(十五)——事务传播行为(基础篇)
  11. python中处理WordNet
  12. Java 2 实用教程 第一章 Java入门
  13. 关于Base32和Base64的一点区分注意
  14. c语言实验:厘米换算英尺英寸
  15. Java处理图片报错:two SOF markers
  16. 征稿 | 听你聊科研,轻松赚稿费!
  17. Spring boot整合Drools、flowable决策引擎解决方案
  18. 建设银行对银行系金融科技转型的战略与思考
  19. 关于表的创建(第二次作业)
  20. oracle付款汇兑损益怎么产生,汇兑损益产生的原因及会计处理原则是什么

热门文章

  1. 怎样查看和修改配置Git用户名和邮箱
  2. 上班防摸鱼插件(知乎页面)
  3. 卓海科技冲刺创业板:拟募资5.47亿 相宇阳控制52.9%股权
  4. android录音频谱动画,android频谱实现(离散傅立叶)
  5. matlab diary on,matlab-dlmwrite跟diary输出数据
  6. 「数据库选型」抛弃MongoDB,拥抱PostgreSQL,工作更轻松
  7. 本地宝js爬虫(附代码)
  8. 鼠标滑过显示图片大图效果
  9. R语言学习——安装R语言,安装RStudio
  10. 发表论文查重率是多少?