# abc265

2022-09-08 20:32:27  阅读：50  来源： 互联网

### $$\textbf{F.}$$

void solve(){
int n, d; cin >> n >> d;
vector<int> p(n + 1); for(int i = 1; i <= n; i ++) cin >> p[i];
vector<int> q(n + 1); for(int i = 1; i <= n; i ++) cin >> q[i];

vector<vector<vector<modint>>> dp(n + 1, vector<vector<modint>>(d + 1, vector<modint>(d + 1)));
dp[0][0][0] = modint(1);
for(int i = 1; i <= n; i ++){
vector<vector<modint>> sumX(d + 1, vector<modint>(d + 1));
for(int x = 0; x <= d; x ++) for(int y = 0; y <= d; y ++){
if(x && y) sumX[x][y] = sumX[x - 1][y - 1];
int s = min(p[i], q[i]) - 1;
if(p[i] - s <= x && q[i] - s <= y)
sumX[x][y] += dp[i - 1][x - (p[i] - s)][y - (q[i] - s)];
}
vector<vector<modint>> sumY(d + 1, vector<modint>(d + 1));
for(int x = 0; x <= d; x ++) for(int y = 0; y <= d; y ++){
if(x && y) sumY[x][y] = sumY[x - 1][y - 1];
int s = max(p[i], q[i]) + 1;
if(s - p[i] <= x && s - q[i] <= y)
sumY[x][y] += dp[i - 1][x - (s - p[i])][y - (s - q[i])];
}
vector<vector<modint>> sumZ(d + 1, vector<modint>(2 * d + 1));
int P = min(p[i], q[i]), Q = max(p[i], q[i]);
for(int x = 0; x <= d; x ++) for(int y = 0; y <= 2 * d; y ++){
if(x && y < 2 * d) sumZ[x][y] = sumZ[x - 1][y + 1];
if(y - (Q - P) >= 0 && y - (Q - P) <= d) sumZ[x][y] += dp[i - 1][x][y - (Q - P)];
if(x - (Q - P) - 1 >= 0 && y < d) sumZ[x][y] -= dp[i - 1][x - (Q - P) - 1][y + 1];
}

for(int x = 0; x <= d; x ++) for(int y = 0; y <= d; y ++)
dp[i][x][y] = sumX[x][y] + sumY[x][y] + sumZ[x][y];
}
modint ans(0);
for(int x = 0; x <= d; x ++) for(int y = 0; y <= d; y ++)
ans += dp[n][x][y];
cout << ans.val() << "\n";
}


### $$\textbf{G.}$$

struct Sgt{
private:
#define ls(o) 2 * o
#define rs(o) 2 * o + 1

struct Item{
array<int, 3> once; array<array<ll, 3>, 3> twice;
} ;
vector<Item> tree; vector<array<int, 3>> lazy; int n;

Item merge(Item ls, Item rs){
Item res;
for(int i = 0; i < 3; i ++)
res.once[i] = ls.once[i] + rs.once[i];
for(int i = 0; i < 3; i ++) for(int j = 0; j < 3; j ++)
res.twice[i][j] = ls.twice[i][j] + rs.twice[i][j] + (ll)ls.once[i] * rs.once[j];
return res;
}
void pushup(int o){
tree[o] = merge(tree[ls(o)], tree[rs(o)]);
}
void addtag(int o, array<int, 3> mov){
Item lst = tree[o];
for(int i = 0; i < 3; i ++) tree[o].once[i] = 0;
for(int i = 0; i < 3; i ++) for(int j = 0; j < 3; j ++) tree[o].twice[i][j] = 0;
for(int i = 0; i < 3; i ++)
tree[o].once[mov[i]] += lst.once[i];
for(int i = 0; i < 3; i ++) for(int j = 0; j < 3; j ++)
tree[o].twice[mov[i]][mov[j]] += lst.twice[i][j];
array<int, 3> lzy = lazy[o];
for(int i = 0; i < 3; i ++) lazy[o][i] = mov[lzy[i]];
}
void pushdown(int o){
}

public:
Sgt(int _n = 0, vector<int> val = {}){
n = _n, tree = vector<Item>(4 * n + 100), lazy = vector<array<int, 3>>(4 * n + 100, {0, 1, 2});
auto build = [&](auto build, int o, int L, int R) -> void {
if(L == R) return tree[o].once[val[L]] ++, void();
int M = (L + R) / 2; build(build, ls(o), L, M), build(build, rs(o), M + 1, R); pushup(o);
} ;
build(build, 1, 0, n - 1);
}
void modify(int l, int r, array<int, 3> mov){
auto modify = [&](auto modify, int o, int L, int R) -> void {
if(l <= L && R <= r) return addtag(o, mov), void();
pushdown(o); int M = (L + R) / 2;
if(l <= M) modify(modify, ls(o), L, M);
if(r > M) modify(modify, rs(o), M + 1, R);
pushup(o);
} ;
modify(modify, 1, 0, n - 1);
}
Item query(int l, int r){
auto query = [&](auto query, int o, int L, int R) -> Item {
if(l <= L && R <= r) return tree[o];
pushdown(o); int M = (L + R) / 2;
if(r <= M) return query(query, ls(o), L, M);
if(l > M) return query(query, rs(o), M + 1, R);
return merge(query(query, ls(o), L, M), query(query, rs(o), M + 1, R));
} ;
return query(query, 1, 0, n - 1);
}
} ;

void solve(){
int n, q; cin >> n >> q;
vector<int> a(n + 1); for(int i = 1; i <= n; i ++) cin >> a[i];
Sgt sgt(n + 1, a);
while(q --){
int opt; cin >> opt;
if(opt == 1){
int L, R; cin >> L >> R; auto res = sgt.query(L, R);
cout << res.twice[1][0] + res.twice[2][0] + res.twice[2][1] << "\n";
}
if(opt == 2){
int L, R, S, T, U; cin >> L >> R >> S >> T >> U;
sgt.modify(L, R, {S, T, U});
}
}
}


### $$\textbf{H.}$$

• 当 $$p _ i > q _ i$$ 时. 则此时相当于有一堆 $$p _ i - q _ i - 1$$ 个石头构成的堆, 每次每人可以取走正整数枚棋子. 称这样一行为关键行.
• 当 $$p _ i < q _ i$$ 时. 则此时先手, 后手互不干扰且双方都想用这个棋子多走几轮. 于是此时先手可以多走 $$p _ i - 1$$ 轮, 后手可以多走 $$w - q _ i$$ 轮. 称这一行为非关键行.

• 若 $$P > Q$$. 则先手第一步任意操作关键行. 对于后手的每一步:

• 若其操作关键行, 则先手尽量操作关键行, 若不行则操作非关键行. 则之后双方都只能操作非关键行, 因为 $$P > Q$$, 所以后手一定会比先手先操作完, 从而输掉比赛.
• 若其操作非关键行, 则先手同样操作非关键行, 此时 $$P - Q$$ 不变.

于是此时先手必胜. (简而言之就是无论关键行谁赢, 最后先手都能耗死后手)

• 若 $$P < Q$$. 同理可知此时后手必胜.

• 若 $$P = Q$$. 则对于双方来说, 非关键行都是无用的. (因为若一方操作非关键行, 另一方必然操作关键行, 根据上面的讨论从而获胜. 故双方都只会在关键行操作完之后去操作非关键行, 此时的输赢和关键行内的输赢是相同的)

注意到关键行本质上是一个若干堆石头的 Nim 游戏, 所以此时先手获胜当且仅当 $$\bigoplus _ {i, p _ i > q _ i} (p _ i - q _ i - 1) \neq 0$$.

• 根据 $$f _ T (i, T) = f _ T (i, -T)$$ 可以砍去一个 $$\dfrac{1}{2}$$ 的常数.
• 先 $$\mathcal{O}(h w ^ 2)$$ 预处理出所有的 $$f _ S (i, S)$$, 之后每计算出一个 $$f _ T (i, T)$$ 就直接往答案里更新. 这样 $$f _ T (i, T)$$ 可以滚动优化到第一维 $$i$$. 以达到卡空间的目的.

void solve(){
int h, w; cin >> h >> w;
int maxS = 1 << (__lg(w) + 1);

vector<vector<modint>> dpS(h + 1, vector<modint>(maxS + 1));
dpS[0][0] = modint(1);
for(int i = 0; i < h; i ++)
for(int S = 0; S <= maxS; S ++)
if(dpS[i][S].val())
for(int s = 0; s < w; s ++)
dpS[i + 1][S ^ s] += dpS[i][S] * modint(w - 1 - s);

vector<modint> sumdpS(h + 1);
for(int i = 0; i <= h; i ++)
for(int S = 0; S <= maxS; S ++)
sumdpS[i] += dpS[i][S];

Binom binom(h);
modint ans(0);

vector<modint> dpT((h + 1) * w + 1); dpT[0] = modint(1);
for(int i = 0; i <= h; i ++){
for(int T = 1; T <= i * w; T ++)
ans += binom.binom(h, i) * dpT[T] * sumdpS[h - i];
for(int S = 1; S <= maxS; S ++)
ans += binom.binom(h, i) * dpT[0] * dpS[h - i][S];
if(i == h)
break;

vector<modint> sum((i + 1) * w + w + w + 1);
for(int T = -w; T <= (i + 1) * w + w; T ++){
sum[T + w] = dpT[abs(T)];
if(T >= -w + 2)
sum[T + w] += sum[T - 2 + w];
}

vector<modint> newdpT((h + 1) * w + 1);
for(int t = -w; t <= w; t ++)
newdpT[0] += dpT[abs(t)] * modint((w - abs(t)) / 2);
for(int T = 1; T <= (i + 1) * w; T ++){
if(w % 2 == 0){
newdpT[T] = newdpT[T - 1];
newdpT[T] += (sum[T + w - 2 + w] - sum[T - 2 + w]);
newdpT[T] -= (sum[T - 1 + w] - sum[T - w - 1 + w]);
}
if(w % 2 == 1){
newdpT[T] = newdpT[T - 1];
newdpT[T] += (sum[T + w - 2 + w] - sum[T - 1 + w]);
newdpT[T] -= (sum[T - 2 + w] - sum[T - w - 1 + w]);
}
}
dpT = newdpT;
}

cout << ans.val() << "\n";
}


2. 关于本站的所有留言、评论、转载及引用，纯属内容发起人的个人观点，与本站观点和立场无关；
3. 关于本站的所有言论和文字，纯属内容发起人的个人观点，与本站观点和立场无关；
4. 本站文章均是网友提供，不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属；如您发现该文章侵犯了您的权益，可联系我们第一时间进行删除；
5. 本站为非盈利性的个人网站，所有内容不会用来进行牟利，也不会利用任何形式的广告来间接获益，纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。