E. Sum of Matchings 代码
蜗蜗的数列 代码
H. Crystalfly 代码
F. Towers 代码
C. Werewolves 代码
P4766 CERC2014 Outer space invaders 代码
H. The Boomsday Project 代码
Perfect Matchings 代码
Binary Strings 代码
ACM Tax 代码
代码
代码
写这玩意真的麻了!!!!
vector<int> G[N], v;
bool dis[N];
int n;
int c2(int x){return x*(x-1)/2;}
// 判断是否 e 在两个范围内;
bool di(int a, int b, int c, int d, int e){return (e <= n && e >= a && e <= b) || (e > n && e <= d && e >= c);}
// 求环
void dfs(int u)
{
for(auto x : G[u]) if(!dis[x]) dis[x] = 1, dfs(x), v.push_back(x);
return ;
}
int main()
{
LL ans = 0;
scanf("%d", &n);
for(int i = -n+1;i <= n;i ++)
{
int x, y;
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
for(int i = 1;i <= n;i ++) // 因为是一边指向另一边, 最大匹配数 = 边的数量+1>>1 ;
if(!dis[i])
{
v.clear();
dfs(i);
int siz = v.size();
int a, b, c, d; a = c = n<<2, b = d = 0;
for(auto x : v)
if(x > n) d = max(d, x), c = min(c, x);
else a = min(a, x), b = max(b, x);
ans += 1LL*(siz+1)/2*a*(c-n)*(n-b+1)*(2*n-d+1);
// 先求全部的
for(int l = 0;l < siz;l ++)
{
int a, b, c, d, e = v[(l-1+siz)%siz];
a = c = n<<2+1, b = d = 0;
if(v[l] > n) d = c = v[l];
else a = b = v[l];
for(int r = (l+1)%siz;(r+1)%siz != l;(r += 1) %= siz)
{
if(v[r] > n) d = max(d, v[r]), c = min(c, v[r]);
else a = min(a, v[r]), b = max(b, v[r]);
int k = v[(r+1)%siz];
if(di(a, b, c, d, e) || di(a, b, c, d, k)) continue;
// 从这开始 都是 sb 求 范围
vector<int> q, s;
q.push_back(0); q.push_back(n+1);
s.push_back(n); s.push_back(n+n+1);
e <= n ? q.push_back(e) : s.push_back(e);
k <= n ? q.push_back(k) : s.push_back(k);
sort(all(q));
sort(all(s));
int aa = *(upper_bound(q.begin(), q.end(), a)-1),
bb = *lower_bound(q.begin(), q.end(), b),
cc = *(upper_bound(all(s), c)-1),
dd = *lower_bound(all(s), d);
ans += 1LL*((r-l+siz)%siz+1)/2*(a-aa)*(bb-b)*(c-cc)*(dd-d);
}
}
}
差分真神奇,原来还可以这样差分。
int fib[N], a[N];
int n, q, m, num = 0;
void modify(int &a, int b)
{
if(a) -- num; a = (a+b)%m; if(a) ++ num;
}
int main()
{
scanf("%d%d%d", &n, &q, &m);
for(int i = 1;i <= n;i ++) scanf("%d", a+i);
fib[1] = 1;
for(int i = 2;i <= n;i ++) fib[i] = (fib[i-2] + fib[i-1])%mod;
for(int i = 1;i <= n;i ++){
int x;
scanf("%d", &x);
a[i] -= x;
}
for(int i = n;i >= 2;i --)
a[i] = (a[i] - a[i-1]%m - a[i-2]%m + 2*m)%m, num += a[i] != 0;
num += a[1] != 0;
while(q --)
{
char c[2]; int l, r, f = 1;
scanf("%s%d%d", c, &l, &r);
if(c[0] == 'B') f = -1;
modify(a[l], f*fib[1]);
if(r+1 <= n) modify(a[r+1], -f*fib[r-l+2]);
if(r+2 <= n) modify(a[r+2], -f*fib[r-l+1]);
P(!num);
}
return 0;
}
可以算模板题吧,链用树链剖分,个数用主席树统计,再进行查找,查找好像见过类似方法
const int N = 1e5+10, mod = 1e9+7, len = 6100;
void add(int &a, LL b){a = (a+b)%mod;return ;}
LL qsm(LL u, int v){LL ans = 1;for(;v;v>>=1, u=u*u%mod) if(v&1) ans = ans*u%mod;return ans;}
LL inv(int x){return qsm(x, mod-2);}
int h[N],ne[N],e[N],son[N],siz[N], idx, w[N], val[N];
int top[N],fa[N],deep[N],dfn[N],rnk[N],num;
void add(int u, int v, int x){w[idx] = x;e[idx] = v;ne[idx] = h[u]; h[u] = idx++; return ;}
vector<PII> v, c;
int sum = 0;
int rt[N], tr[N<<4], ls[N<<4], rs[N<<4];
void modify(int &u, int v, int l, int r, int x)
{
u = ++idx;
ls[u] = ls[v]; rs[u] = rs[v]; tr[u] = tr[v] + 1;
if(l == r) return ;
x <= mid ? modify(ls[u], ls[v], l, mid, x) : modify(rs[u], rs[v], mid+1, r, x);
return ;
}
int quary(int l, int r, int k)
{
if(l == r) return l;
int sum = 0;
for(auto x : v) sum += tr[ls[x.first]]*x.second;
if(sum >= k) for(auto &x : v) x.first = ls[x.first];
else for(auto &x : v) x.first = rs[x.first];
return sum >= k ? quary(l, mid, k) : quary(mid+1, r, k-sum);
}
void dfs1(int u,int f) {
siz[u] = 1;
fa[u] = f;
deep[u]=deep[f]+1;
for (int i = h[u]; ~i; i = ne[i])
{
int t = e[i];
if(t == f)continue;
dfs1(t, u); val[t] = w[i];
siz[u] += siz[t];
if(siz[t] > siz[son[u]]) son[u] = t;//娌℃湁0杩欎釜鐐癸紱鏄繖鏍峰啓
}
return ;
}
void dfs2(int u, int t) {
dfn[u] = ++num; modify(rt[dfn[u]], rt[dfn[u]-1], 1, 100000, val[u]);
top[u] = t;
rnk[num] = u;
if(!son[u])return ;
dfs2(son[u], t);
for(int i = h[u]; ~i;i = ne[i])
{
int j = e[i];
if(j==son[u]||j==fa[u])continue;
dfs2(j,j);
}
return ;
}
void LCA(int x, int y)
{
while(top[x] != top[y])
{
if(deep[top[x]] < deep[top[y]]) swap(x, y);
v.push_back({rt[dfn[x]], 1}); v.push_back({rt[dfn[top[x]]-1], -1});
sum += deep[x] - deep[fa[top[x]]];
x = fa[top[x]];
}
if(deep[x] < deep[y])swap(x, y);
v.push_back({rt[dfn[x]], 1});
v.push_back({rt[dfn[y]], -1});
sum += deep[x] - deep[y];
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
int n, q;
scanf("%d", &n);
for(int i = 1;i <= n;i ++) h[i] = -1, son[i] = 0;
num = 0; idx = 0;
for(int i = 2;i <= n;i ++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
idx = 0;
dfs1(1, 0); dfs2(1, 0);
scanf("%d", &q);
while(q --)
{
int l, r;
scanf("%d%d", &l, &r);
v.clear(); sum = 0;
LCA(l, r); c = v; // vector<int> v, c 是节点数组 方便log*log 而不是log*log*log
++ sum;
int k = quary(1, 100000, sum/2);
v = c;
k += quary(1, 100000, sum+1>>1);
printf("%d", k/2);
puts(k&1 ? ".5" : ".0");
}
}
return 0;
}
直接递归就能算,亏我还数位dp了半天
const int N = 1e5+10, mod = 1e9+7;
void add(int &a, LL b){a = (a+b)%mod;return ;}
void add(LL &a, LL b){a = (a+b)%mod;return ;}
LL qsm(LL u, int v){LL ans = 1;for(;v;v>>=1, u=u*u%mod) if(v&1) ans = ans*u%mod;return ans;}
LL inv(int x){return qsm(x, mod-2);}
struct point{LL a[4];};
point be = {1, 0, 0, 1};
point operator * (point a, point b)
{
point c = {0};
add(c.a[0], a.a[0]*b.a[0] + a.a[0]*b.a[2] + a.a[1]*b.a[0]);
add(c.a[1], a.a[0]*b.a[1] + a.a[0]*b.a[3] + a.a[1]*b.a[1]);
add(c.a[2], a.a[3]*b.a[0] + a.a[2]*b.a[2] + a.a[2]*b.a[0]);
add(c.a[3], a.a[3]*b.a[1] + a.a[2]*b.a[1] + a.a[2]*b.a[3]);
return c;
}
point operator + (point a, point b){for(int i = 0;i < 4;i ++) add(a.a[i], b.a[i]);return a;}
void prin(point a){for(int i = 0;i < 4;i ++) cout<<a.a[i]<<' ';cout<<endl;return ;}
point se(LL k)
{
point c = be, s = c; k --;
for(;k;k>>=1, c = c*c) if(k&1) s = s*c;
return s;
}
point se(LL s, int k)
{
if(s <= 0) return {0, 0, 0, 0};
if(s == 1) return se(k);
LL l = s>>1, r = s-l;
point t = se(l, k);
if(l == r) return t + t*se(l*k);
else return t + t*se(l*k) + se(s*k);
}
int main()
{
int t;
scanf("%d", &t);
for(int i = 1;i <= t;i ++)
{
LL L, R, k;
scanf("%lld%lld%lld", &L, &R, &k);
-- L;
point l = se(R/k, k), r = se(L/k, k);
int ans = 0 ;
for(int i = 0;i < 4;i ++) add(ans, l.a[i] - r.a[i]);
add(ans, mod);
printf("Case %d: %d\n",i, ans);
}
return 0;
}
容了半天没容明白,晚上再想想
vector<int> v[N];
int dp[4100][8100][2], siz[4100], n, in[N];
void dfs(int u, int fa)
{
siz[u] = 1;
dp[u][0][0] = 1;
for(auto x : v[u])
{
if(x == fa) continue;
dfs(x, u);
for(int i = siz[u];i >= 0;i --)
for(int j = siz[x];j >= 1;j --)
add(dp[u][i+j][0], 1LL*dp[u][i][0]*(dp[x][j][0] + dp[x][j][1])),
add(dp[u][i+j][1], 1LL*dp[u][i][1]*(dp[x][j][0] + dp[x][j][1]) + 1LL*dp[u][i][0]*dp[x][j-1][0]);
siz[u] += siz[x];
}
return ;
}
int main()
{
scanf("%d", &n);
for(int i = 2*n-1;i >= 1;i --)
{
int a, b;
scanf("%d%d", &a, &b);
v[a].push_back(b);
v[b].push_back(a);
}
in[0] = 1;
for(int i = 1;i <= n;i ++) in[i] = 1LL*in[i-1]*((i<<1)-1)%mod;
dfs(1, 0);
int ans = in[n];
for(int i = 1;i <= n;i ++)
add(ans, 1LL*(i&1 ? -1 : 1)*(dp[1][i][0]+dp[1][i][1])*in[n-i]);
add(ans, mod);
cout<<ans<<endl;
return 0;
}
单调栈
int d[510], k[510], c[510], e[N];
int a[N], idx = 0;
LL dp[N];
int main()
{
int n, m, r;
scanf("%d%d%d", &n, &m, &r);
for(int i = 1;i <= n;i ++) scanf("%d%d%d", d+i, k+i, c+i);
for(int i = 1;i <= m;i ++)
{
int p, q;
scanf("%d%d", &p, &q);
while(q --) ++ idx, a[idx] = p;
}
sort(a+1, a+idx+1);
memset(dp, 0x3f, sizeof dp);
dp[0] = 0; a[0] = -1e9;
for(int i = 1;i <= idx;i ++)
{
// dp[i] = min(dp[i], dp[i-1]+r);
for(int j = 1;j <= n;j ++){
while(a[i]-a[e[j]]+1 > d[j] || i-e[j]+1 > k[j]) ++ e[j];
dp[i] = min(dp[i], dp[e[j]-1] + c[j]);
}
}
cout<<dp[idx]<<endl;
return 0;
}
相当于分割吧 n 3 n^3 n3 暴力区间dp
pair<PII, int> a[N];
vector<int> v;
bool dis[610][610];
int dp[610][610], n;
int dfs(int l, int r)
{
if(dis[l][r]) return dp[l][r];
dis[l][r] = 1;
int c = -1;
for(int i = 1;i <= n;i ++)
{
int x = a[i].first.first, y = a[i].first.second;
if(x >= l && y <= r && (c == -1 || a[i].second > a[c].second)) c = i;
}
if(c == -1) return dp[l][r] = 0;
int x = a[c].first.first, y = a[c].first.second;
while(x <= y) dp[l][r] = min(dp[l][r], dfs(l, x-1)+dfs(x+1, r)+a[c].second), ++x;
return dp[l][r];
}
int main()
{
int t;
scanf("%d", &t);
memset(dp, 0x3f, sizeof dp);
while(t --)
{
scanf("%d", &n);
for(int i = 1;i <= n;i ++) scanf("%d%d%d", &a[i].first.first, &a[i].first.second, &a[i].second), v.push_back(a[i].first.first),v.push_back(a[i].first.second);
v.push_back(-1);
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
for(int i = 1;i <= v.size();i ++)for(int j = 1;j <= v.size();j ++) dis[i][j] = 0, dp[i][j] = 0x3f3f3f3f;
for(int i = 1;i <= n;i ++){
int &x = a[i].first.first;
int &y = a[i].first.second;
x = lower_bound(v.begin(), v.end(), x) - v.begin();
y = lower_bound(v.begin(), v.end(), y) - v.begin();
}
cout<<dfs(1, v.size()-1)<<endl;
v.clear();
}
return 0;
}
const int N = 5e5+10, mod = 998244353, len = 6100;
void add(int &a, LL b){a = (a+b)%mod;return ;}
int dp[3100][12200], co[N], color, n, siz[N], num[N], c[12200], de[N];
vector<int> v[N];
int ans = 0;
// c 辅助数组 co[i] i的颜色 len = 6000负数变正数 siz[i] i的子树大小 num[i] i
void dfs(int u, int fa)
{
for(int i = len-num[color-1];i <= len+num[color-1];i ++) dp[u][i] = c[i] = 0;
dp[u][(co[u] == color ? 1 : -1)+len] = 1;
de[u] = co[u] == color;
siz[u] = 1;
for(auto x : v[u])
{
if(x == fa) continue;
dfs(x, u);
for(int i = len-num[color];i <= num[color] + len;i ++) c[i] = dp[u][i];
int up = de[u], down = min(num[color], siz[u]-de[u]);
for(int i = len-down;i <= len+up;i ++)
for(int j = -min(siz[x]-de[x], num[color]);j <= de[x];j ++)
add(dp[u][i+j], 1LL*c[i]*dp[x][len+j]);
siz[u] += siz[x];de[u] += de[x]; // 好像是 可以 防止一条链 ,这样上面就要是i+j = i + j
}
for(int i = len+1;i <= num[color]+len;i ++) add(ans, dp[u][i]);
}
int main()
{
scanf("%d", &n);
for(int i = 1;i <= n;i ++) scanf("%d", co+i), num[co[i]] ++;
for(int i =2;i <= n;i ++) {
int a, b;
scanf("%d%d", &a, &b);
v[a].push_back(b);
v[b].push_back(a);
}
for(int i = 1;i <= n;i ++)
color = i, dfs(1, 0);
cout<<ans<<endl;
return 0;
}
int h[N];
vector<int> v[N];
LL cost[N];
void dfs(int u, int fa)
{
int t = 0;
for(auto x : v[u])
{
if(x == fa) continue;
dfs(x, u);
t = max(t, h[x]);
cost[u] += cost[x];
}
if(t < h[u]) cost[u] += h[u] - t;
else h[u] = t;
// cout<<u<<' '<<h[u]<<' '<<cost[u]<<' '<<t<<endl;
return ;
}
int main()
{
int n, pos = 1;
scanf("%d", &n);
for(int i = 1;i <= n;i ++) scanf("%d", h+i), pos = h[pos] < h[i] ? i : pos;
for(int i = 2;i <= n;i ++)
{
int a, b;
scanf("%d%d", &a, &b);
v[a].push_back(b); v[b].push_back(a);
}
LL z = 0;
vector<int> ans; ans.clear(); ans.push_back(0);
for(auto x : v[pos])
dfs(x, pos), ans.push_back(h[x]), z += cost[x];
sort(ans.begin(), ans.end(), greater<int>());
// cout<<h[3]<<' '<<cost[3]<<endl;
z += max(h[pos]-ans[1], 0) + max(h[pos] - ans[0], 0);
cout<<z<<endl;
return 0;
}
t<=3说明只能得到一个子树或者另一颗子树的根节点,然后分类成三种树
LL dp[3][N];
int a[N], t[N];
vector<int> v[N];
void dfs(int u, int fa)
{
int ma = 0;
PII c[3] = {{1e18, 0}, {1e18, 0}}; // 求dp[2][x] -
for(auto x : v[u])
{
if(x == fa) continue;
dfs(x, u);
dp[2][u] += dp[1][x]; ma = max(ma, a[x]);
c[2] = {dp[1][x]-dp[2][x], x}; sort(c, c+3);
}
dp[1][u] = dp[2][u] + ma;
for(auto x : v[u])
{
if(x == fa || t[x] < 3) continue;
dp[1][u] = max(dp[1][u], dp[2][u] + dp[0][x] - dp[1][x] - c[c[0].second == x].first);
}
dp[2][u] += a[u];
dp[0][u] = dp[1][u] + a[u];
}
int main()
{
int _;
scanf("%d", &_);
while(_ --)
{
int n;
scanf("%d", &n);
for(int i = 1;i <= n;i ++) scanf("%d", a+i);
for(int i = 1;i <= n;i ++) scanf("%d", t+i);
for(int i = 2;i <= n;i ++)
{
int a, b;
scanf("%d%d", &a, &b);
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1, 0);
printf("%lld\n", dp[0][1]);
for(int i = 1;i <= n;i ++) dp[0][i] = dp[1][i] = dp[2][i] = 0, v[i].clear();
}
return 0;
}