26.10.5qbxt集训day5
T1

暴力。
点击查看代码
#include <iostream>
#include <string>
#include <cstring>
using std::cin;
using std::cout;
const int N = 13;
int n;
int cnt;
int r[N];
int siz[N];
int f[N][N];
std::string t[N];
std::string ps[(int)3e5 + 10];
void get(int x, std::string s)
{
if (x == n + 1)
{
ps[++cnt] = s;
return;
}
for (char c = 'a'; c <= 'c'; ++c)
{
s.push_back(c);
get(x + 1, s);
s.pop_back();
}
}
int main()
{
freopen("string.in", "r", stdin);
freopen("string.out", "w", stdout);
int m;
cin >> n >> m;
get(1, " ");
for (int i = 1; i <= m; ++i)
{
cin >> t[i] >> r[i];
siz[i] = t[i].size();
t[i] = ' ' + t[i];
}
int ans = 0;
for (int i = 1; i <= cnt; ++i)
{
int cc = 0;
for (int j = 1; j <= m; ++j)
{
memset(f, 0, sizeof(f));
for (int x = 1; x <= n; ++x)
{
for (int y = 1; y <= siz[j]; ++y)
{
if (ps[i][x] == t[j][y])
f[x][y] = f[x - 1][y - 1] + 1;
f[x][y] = std::max(std::max(f[x][y], f[x][y - 1]), f[x - 1][y]);
}
}
if (f[n][siz[j]] > r[j])
cc++;
}
if (cc <= 1)
ans++;
}
cout << ans << '\n';
return 0;
}
T2

推式子。
点击查看代码
#include <iostream>
using std::cin;
using std::cout;
const int N = 5e4 + 10;
const int mod = 1e9 + 7;
int pw2[N];
int sm[N];
int main()
{
freopen("rand.in", "r", stdin);
freopen("rand.out", "w", stdout);
pw2[0] = 1;
int inv2 = (-mod / 2 + mod);
for (int i = 1; i <= 5e4; ++i)
pw2[i] = 1ll * pw2[i - 1] * inv2 % mod;
for (int i = 1; i <= 5e4; ++i)
sm[i] = (sm[i - 1] + pw2[i]) % mod;
int t;
cin >> t;
while (t--)
{
int n, k;
cin >> n >> k;
cout << (sm[k] + 1ll * n * pw2[k] % mod) % mod << '\n';
}
return 0;
}
T3

点击查看std
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=505,mods=1e9+7;
int pows(int a,int b)
{
if(b==0)return 1;
int res=pows(a,b>>1);
res=res*res%mods;
if(b&1)res=res*a%mods;
return res;
}
int n,f[N][N],mk[N],w[N],sz[N],dp[2][N],g[N][N],C[N][N],jc[N];
vector<pair<int,int> >e[N];
void dfs(int x)
{
mk[x]=1;
for(auto [c,sm]:e[x])
{
if(mk[c])continue;
dfs(c);
}
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(auto [c,sm]:e[x])
{
if(mk[c])continue;
sm=sm*sm%mods;
for(int i=1,nw=sm; i<=sz[c]; i++,nw=nw*sm%mods)f[c][i]=f[c][i]*nw%mods;
for(int i=1; i<=sz[c]; i++)
{
for(int j=i; j<=sz[c]; j++)
{
int ans=f[c][j]*C[j-1][i-1]%mods;
if(j-i&1)g[c][i]-=ans;
else g[c][i]+=ans;
}
g[c][i]%=mods;
}
for(int i=0; i<=sz[x]; i++)
{
for(int j=1; j<=sz[c]; j++)
{
dp[1][i+j]+=dp[0][i]*g[c][j]%mods*C[i+j][j]%mods;
}
}
sz[x]+=sz[c];
for(int i=0; i<=sz[x]; i++)dp[0][i]=dp[1][i]%mods,dp[1][i]=0;
}
if(x>1)for(int i=0; i<=sz[x]; i++)dp[1][i+1]+=dp[0][i]*(i+1)%mods;
else for(int i=0; i<=sz[x]; i++)dp[1][i+1]=dp[0][i];
sz[x]++;
for(int i=0; i<=sz[x]; i++)dp[0][i]=dp[1][i]%mods,dp[1][i]=0;
for(int i=1; i<=sz[x]; i++)
{
for(int j=i; j<=sz[x]; j++)
{
f[x][i]+=dp[0][j]*C[j-1][i-1]%mods;
}
f[x][i]%=mods;
}
mk[x]=0;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
jc[0]=1;
for(int i=1; i<=n; i++)jc[i]=jc[i-1]*i%mods;
for(int i=0; i<=n; i++)C[i][0]=1;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mods;
}
}
for(int i=1; i<n; i++)
{
int x,y,z;
cin>>x>>y>>z;
e[x].push_back({y,z});
e[y].push_back({x,z});
}
dfs(1);
cout<<(f[1][1]%mods*pows(jc[n-1],mods-2)%mods+mods)%mods;
}
T4

点击查看std
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned char u8;
struct Op
{
int t, x, y;
ll v;
};
/* ---------- 快读 ---------- */
struct FastIn
{
static const int SZ = 1 << 20;
char b[SZ];
int p = 0, e = 0;
inline char gc()
{
if (p == e)
{
e = (int)fread(b, 1, SZ, stdin);
p = 0;
if (!e) return 0;
}
return b[p++];
}
template <class T>
inline bool read(T &x)
{
char c;
do
{
c = gc();
if (!c) return false;
}
while (c <= ' ');
bool neg = false;
if (c == '-')
{
neg = true;
c = gc();
}
x = 0;
while (c > ' ')
{
x = x * 10 + (c - '0');
c = gc();
}
if (neg) x = -x;
return true;
}
};
/* ---------- 快写 ---------- */
struct FastOut
{
static const int SZ = 1 << 22;
char b[SZ];
int p = 0;
inline void flush()
{
if (p)
{
fwrite(b, 1, p, stdout);
p = 0;
}
}
inline void put(ll x)
{
char tmp[24];
int t = 0;
do
{
tmp[t++] = (char)('0' + x % 10);
x /= 10;
}
while (x);
while (t) b[p++] = tmp[--t];
b[p++] = '\n';
if (p > SZ - 40) flush();
}
~FastOut()
{
flush();
}
} fout;
int main()
{
FastIn fin;
int n, m;
fin.read(n);
fin.read(m);
vector<ll> w(n + 1);
for (int i = 1; i <= n; i++) fin.read(w[i]);
/* ---------- CSR 邻接表 ---------- */
vector<int> eu(n), ev(n);
vector<int> adjHead(n + 1, -1);
vector<int> adjTo(2 * n + 5), adjEid(2 * n + 5), adjNext(2 * n + 5);
{
int ec = 0;
for (int i = 1; i < n; i++)
{
int x, y;
fin.read(x);
fin.read(y);
adjTo[ec] = y;
adjEid[ec] = i;
adjNext[ec] = adjHead[x];
adjHead[x] = ec++;
adjTo[ec] = x;
adjEid[ec] = i;
adjNext[ec] = adjHead[y];
adjHead[y] = ec++;
}
}
vector<Op> ops(m);
for (int i = 0; i < m; i++)
{
int t;
fin.read(t);
if (t == 1)
{
int x, y;
fin.read(x);
fin.read(y);
ops[i] = {1, x, y, 0};
}
else if (t == 2)
{
int x;
ll v;
fin.read(x);
fin.read(v);
ops[i] = {2, x, 0, v};
}
else
{
int x;
fin.read(x);
ops[i] = {3, x, 0, 0};
}
}
/* ---------- 定根 / dfn / 倍增 ---------- */
vector<int> par(n + 1, 0), pe(n + 1, 0), dep(n + 1, 0), dfn(n + 1, 0), ord(n + 1);
vector<int> stk(n + 1);
{
int timer = 0, top = 0;
stk[top++] = 1;
while (top)
{
int u = stk[--top];
dfn[u] = ++timer;
ord[timer] = u;
for (int e = adjHead[u]; e != -1; e = adjNext[e])
{
int v = adjTo[e];
if (v == par[u]) continue;
par[v] = u;
pe[v] = adjEid[e];
dep[v] = dep[u] + 1;
stk[top++] = v;
}
}
}
int LOG = 1;
while ((1 << LOG) <= n) LOG++;
int W = n + 1;
vector<int> up(LOG * W, 0);
for (int i = 1; i <= n; i++) up[i] = par[i];
for (int k = 1; k < LOG; k++)
{
int off = k * W, pr = (k - 1) * W;
for (int i = 1; i <= n; i++) up[off + i] = up[pr + up[pr + i]];
}
auto lca = [&](int a, int b) -> int
{
if (dep[a] < dep[b])
{
int t = a;
a = b;
b = t;
}
int d = dep[a] - dep[b];
while (d)
{
int k = __builtin_ctz((unsigned)d);
a = up[k * W + a];
d &= d - 1;
}
if (a == b) return a;
for (int k = LOG - 1; k >= 0; k--)
{
int ua = up[k * W + a], ub = up[k * W + b];
if (ua != ub)
{
a = ua;
b = ub;
}
}
return par[a];
};
/* ---------- 分块参数与工作区(全部一次分配) ---------- */
int B = max(1, (int)(sqrt((double)n) * 1.5));
int maxV = 4 * B + 10; // 虚点上限
int maxP = 16 * B + 16; // piece 上限
int ARRN = max(n + 1, maxP + 2);
vector<u8> active(n + 1, 0); // 边激活状态
vector<int> vmap(n + 1, -1), posPiece(n + 1, -1), pieceOf(n + 1, 0);
vector<ll> sumV(ARRN, 0), oldSum(ARRN, 0); // sumV: 本块 tag;oldSum: 上一块待下推 tag
int oldSumLen = 0; // 上一块映射(piece/comp)的长度
vector<ll> psize(ARRN, 0), pbaseW(ARRN, 0), contrib(ARRN, 0);
vector<int> lastP(ARRN, 0);
vector<int> vnodes(maxV), vpar(maxV), vdepV(maxV), ordV(maxV), stV(maxV);
vector<int> vhead(maxV), vto(maxV), vnext(maxV);
vector<int> pts(maxV);
vector<int> eidOfChild(maxV), N_id(maxV), inS(maxV, -1), que(maxV);
vector<u8> fpar(maxV);
struct VE
{
int v, p, segStart, segLen;
int idE, idU, idP, idB;
u8 uniform, twoRun, cu, cp;
};
vector<VE> ve(maxV);
vector<int> bigBuf(n + maxV + 5);
/* 无翻转块专用 */
vector<u8> vis(n + 1, 0);
vector<int> bq(n + 1);
vector<ll> compSum(n + 1), compSize(n + 1);
int pushStamp = 0, stampInS = 0;
/* ---------- 逐块处理 ---------- */
for (int bl = 0; bl < m; bl += B)
{
int br = min(m, bl + B);
bool hasFlip = false, hasUpd = false, hasQuery = false;
for (int i = bl; i < br; i++)
{
if (ops[i].t == 1) hasFlip = true;
else if (ops[i].t == 2) hasUpd = true;
else hasQuery = true;
}
bool needPieces = hasUpd || hasQuery;
/* ==========================================================
无翻转块:连通关系不变,BFS 标号后每个操作 O(1)
========================================================== */
if (!hasFlip)
{
memset(vis.data(), 0, (size_t)(n + 1));
int compCnt = 0;
for (int st = 1; st <= n; st++)
{
if (vis[st]) continue;
compCnt++;
ll s = 0;
int sz = 0, qh = 0, qt = 0;
bq[qt++] = st;
vis[st] = 1;
while (qh < qt)
{
int u = bq[qh++];
w[u] += oldSum[pieceOf[u]]; // 融合:消耗上一块 tag
pieceOf[u] = compCnt;
s += w[u];
sz++;
for (int e = adjHead[u]; e != -1; e = adjNext[e])
{
int v = adjTo[e];
if (!vis[v] && active[adjEid[e]])
{
vis[v] = 1;
bq[qt++] = v;
}
}
}
compSum[compCnt] = s;
compSize[compCnt] = sz;
}
if (oldSumLen)
{
fill(oldSum.begin(), oldSum.begin() + oldSumLen + 1, 0);
oldSumLen = 0;
}
fill(sumV.begin(), sumV.begin() + compCnt + 1, 0);
for (int i = bl; i < br; i++)
{
const Op &o = ops[i];
if (o.t == 2)
{
int c = pieceOf[o.x];
sumV[c] += o.v;
compSum[c] += o.v * compSize[c];
}
else
{
fout.put(compSum[pieceOf[o.x]]);
}
}
for (int c = 0; c <= compCnt; c++) oldSum[c] = sumV[c];
oldSumLen = compCnt;
continue;
}
/* ==========================================================
有翻转块:虚树 + 拆块
========================================================== */
int kcnt = 0;
pts[kcnt++] = 1;
for (int i = bl; i < br; i++)
{
pts[kcnt++] = ops[i].x;
if (ops[i].t == 1) pts[kcnt++] = ops[i].y;
}
sort(pts.begin(), pts.begin() + kcnt, [&](int a, int b)
{
return dfn[a] < dfn[b];
});
{
int k2 = 0;
for (int i = 0; i < kcnt; i++)
if (i == 0 || pts[i] != pts[i - 1]) pts[k2++] = pts[i];
kcnt = k2;
}
/* 建虚树(前向星,无 push_back) */
int V = 0, ecnt = 0;
fill(vhead.begin(), vhead.begin() + maxV, -1);
auto getV = [&](int u) -> int
{
if (vmap[u] == -1)
{
vmap[u] = V;
vnodes[V] = u;
vpar[V] = -1;
V++;
}
return vmap[u];
};
int stTop = 0;
for (int i = 0; i < kcnt; i++)
{
int u = pts[i];
if (!stTop)
{
stV[stTop++] = getV(u);
continue;
}
int l = lca(u, vnodes[stV[stTop - 1]]);
while (stTop >= 2 && dep[l] <= dep[vnodes[stV[stTop - 2]]])
{
int p2 = stV[stTop - 2], c2 = stV[stTop - 1];
stTop--;
vto[ecnt] = c2;
vnext[ecnt] = vhead[p2];
vhead[p2] = ecnt++;
vpar[c2] = p2;
}
if (dep[l] < dep[vnodes[stV[stTop - 1]]])
{
int lv = getV(l);
int c2 = stV[--stTop];
vto[ecnt] = c2;
vnext[ecnt] = vhead[lv];
vhead[lv] = ecnt++;
vpar[c2] = lv;
}
if (!stTop || vnodes[stV[stTop - 1]] != l) stV[stTop++] = getV(l);
stV[stTop++] = getV(u);
}
while (stTop >= 2)
{
int p2 = stV[stTop - 2], c2 = stV[stTop - 1];
stTop--;
vto[ecnt] = c2;
vnext[ecnt] = vhead[p2];
vhead[p2] = ecnt++;
vpar[c2] = p2;
}
int rootV = stV[0];
/* 虚树建完后重算虚树深度 */
int ocnt = 0;
ordV[ocnt++] = rootV;
vdepV[rootV] = 0;
for (int qi = 0; qi < ocnt; qi++)
{
int u = ordV[qi];
for (int e = vhead[u]; e != -1; e = vnext[e])
{
int c = vto[e];
vdepV[c] = vdepV[u] + 1;
ordV[ocnt++] = c;
}
}
/* piece:0 号是死块 */
int P = 0;
psize[0] = pbaseW[0] = sumV[0] = contrib[0] = 0;
auto newPiece = [&]() -> int
{
int p = ++P;
psize[p] = 0;
pbaseW[p] = 0;
sumV[p] = 0;
contrib[p] = 0;
return p;
};
if (needPieces)
for (int i = 0; i < V; i++) N_id[i] = newPiece();
/* 拆虚边:一次向上游走,在线算两端同色段 */
int veCnt = 0, bufUsed = 0;
for (int c = 0; c < V; c++)
{
if (c == rootV) continue;
int pIdx = vpar[c];
int ov = vnodes[c], op = vnodes[pIdx];
if (dep[ov] < dep[op]) swap(ov, op);
int segStart = bufUsed;
int Ln = 0;
u8 b0 = 0, prev = 0;
int ra = 0, blen = 0;
bool brk = false;
for (int z = ov;; z = par[z])
{
bigBuf[bufUsed++] = z;
if (z == op) break;
u8 s = active[pe[z]];
if (needPieces)
{
if (!Ln)
{
b0 = s;
ra = 1;
brk = false;
}
else if (!brk)
{
if (s == b0) ra++;
else brk = true;
}
if (!Ln || s != prev)
{
prev = s;
blen = 1;
}
else blen++;
}
Ln++;
}
int ei = veCnt++;
eidOfChild[c] = ei;
fpar[ei] = 0;
VE &e = ve[ei];
e.v = c;
e.p = pIdx;
e.segStart = segStart;
e.segLen = Ln + 1;
if (needPieces)
{
if (ra == Ln)
{
/* 整条虚边同色 */
e.uniform = 1;
e.cu = b0;
e.cp = 0;
e.idE = newPiece();
e.idU = e.idP = e.idB = 0;
for (int k = segStart + 1; k < segStart + Ln; k++)
posPiece[bigBuf[k]] = e.idE;
}
else
{
/* 两端同色段 + 可能的交界块,中间是死节点 */
e.uniform = 0;
e.cu = b0;
e.cp = prev;
e.twoRun = (ra + blen == Ln) ? 1 : 0;
e.idU = newPiece();
e.idP = newPiece();
e.idB = e.twoRun ? newPiece() : 0;
e.idE = 0;
for (int k = segStart + 1; k < segStart + Ln; k++)
{
int j = k - segStart;
int pid;
if (e.twoRun)
pid = (j < ra) ? e.idU : (j == ra ? e.idB : e.idP);
else
pid = (j <= ra) ? e.idU : (j >= Ln - blen ? e.idP : -2);
posPiece[bigBuf[k]] = pid;
}
}
}
else
{
e.uniform = e.cu = e.cp = e.twoRun = 0;
e.idE = e.idU = e.idP = e.idB = 0;
}
}
/* 先序一趟分配每个真实节点的 piece,融合上一块 tag 下推 */
if (needPieces)
{
for (int ii = 1; ii <= n; ii++)
{
int u = ord[ii];
w[u] += oldSum[pieceOf[u]]; // 旧映射下推
int c;
int vm = vmap[u];
if (vm >= 0)
{
c = N_id[vm];
}
else
{
int pp = posPiece[u];
c = (pp >= 0) ? pp : (pp == -2 ? 0 : (active[pe[u]] ? pieceOf[par[u]] : 0));
}
pieceOf[u] = c;
if (hasQuery) pbaseW[c] += w[u];
if (hasUpd) psize[c]++;
}
if (oldSumLen)
{
fill(oldSum.begin(), oldSum.begin() + oldSumLen + 1, 0);
oldSumLen = 0;
}
}
/* 求连通块:虚树 BFS + 就地收集 piece(时间戳去重,无 push_back) */
auto getComp = [&](int x, bool upd, ll v) -> ll
{
++pushStamp;
++stampInS;
int sx = vmap[x];
ll curSum = 0;
auto pushP = [&](int p)
{
if (lastP[p] != pushStamp)
{
lastP[p] = pushStamp;
if (upd)
{
sumV[p] += v;
contrib[p] += v * psize[p];
}
else
{
curSum += pbaseW[p] + contrib[p];
}
}
};
int qh = 0, qt = 0;
que[qt++] = sx;
inS[sx] = stampInS;
pushP(N_id[sx]);
while (qh < qt)
{
int u = que[qh++];
/* 子边:u 是父端 */
for (int e2 = vhead[u]; e2 != -1; e2 = vnext[e2])
{
int c = vto[e2];
int ei = eidOfChild[c];
VE &e = ve[ei];
u8 f = fpar[ei];
if (e.uniform)
{
if (((e.cu ^ f) & 1) != 0)
{
pushP(e.idE);
if (inS[c] != stampInS)
{
inS[c] = stampInS;
que[qt++] = c;
pushP(N_id[c]);
}
}
}
else
{
if (((e.cp ^ f) & 1) != 0)
{
pushP(e.idP);
if (e.twoRun) pushP(e.idB);
}
}
}
/* 父边:u 是子端 */
if (u != rootV)
{
int ei = eidOfChild[u];
VE &e = ve[ei];
u8 f = fpar[ei];
if (e.uniform)
{
if (((e.cu ^ f) & 1) != 0)
{
pushP(e.idE);
int p2 = vpar[u];
if (inS[p2] != stampInS)
{
inS[p2] = stampInS;
que[qt++] = p2;
pushP(N_id[p2]);
}
}
}
else
{
if (((e.cu ^ f) & 1) != 0)
{
pushP(e.idU);
if (e.twoRun) pushP(e.idB);
}
}
}
}
return curSum;
};
/* 虚树上翻转路径 */
auto flipPath = [&](int x, int y)
{
int a = vmap[x], b = vmap[y];
while (vdepV[a] > vdepV[b])
{
fpar[eidOfChild[a]] ^= 1;
a = vpar[a];
}
while (vdepV[b] > vdepV[a])
{
fpar[eidOfChild[b]] ^= 1;
b = vpar[b];
}
while (a != b)
{
fpar[eidOfChild[a]] ^= 1;
fpar[eidOfChild[b]] ^= 1;
a = vpar[a];
b = vpar[b];
}
};
for (int i = bl; i < br; i++)
{
const Op &o = ops[i];
if (o.t == 1) flipPath(o.x, o.y);
else if (o.t == 2) getComp(o.x, true, o.v);
else fout.put(getComp(o.x, false, 0));
}
/* 融合:边翻转下推 + posPiece 清理(一次游走) */
for (int ei = 0; ei < veCnt; ei++)
{
bool fl = fpar[ei] != 0;
if (!fl && !needPieces) continue;
VE &e = ve[ei];
int s = e.segStart, len = e.segLen;
if (fl)
{
if (needPieces)
{
for (int k = s; k + 1 < s + len; k++)
{
active[pe[bigBuf[k]]] ^= 1;
posPiece[bigBuf[k]] = -1;
}
}
else
{
for (int k = s; k + 1 < s + len; k++)
active[pe[bigBuf[k]]] ^= 1;
}
}
else
{
for (int k = s; k + 1 < s + len; k++)
posPiece[bigBuf[k]] = -1;
}
}
/* 本块 tag 成为下一块的 pending */
if (needPieces)
{
for (int p = 0; p <= P; p++) oldSum[p] = sumV[p];
oldSumLen = P;
}
for (int i = 0; i < V; i++) vmap[vnodes[i]] = -1;
}
return 0;
}
题解:
https://files.cnblogs.com/files/blogs/832279/sol.pptx?t=1791179927&download=true
讲的题
https://files.cnblogs.com/files/blogs/832279/S-down..pptx?t=1791181857&download=true (不带答案)
https://files.cnblogs.com/files/blogs/832279/S..pptx?t=1791191924&download=true (带答案)
作业:
P4071
P2742
P2260
P10116
P5014
P4345
P2495

浙公网安备 33010602011771号