据说是llsw出的题
我是没上200的丝薄
A. 遗忘十字路
记 f u , K f_{u,K} fu,K表示从 u u u出发,走 K K K次后价值和的最大值。
假设有 m m m个儿子,那么 f u , K = ∑ v f v , K / m + ∑ v ′ f v ′ , K / m + 1 f_{u,K}=\sum_v f_{v,K/m}+\sum_{v'}f_{v',K/m+1} fu,K=∑vfv,K/m+∑v′fv′,K/m+1 。
直接排序即可。应该可以感觉到状态数是线性的。
复杂度 O ( n log n ) O(n\log n) O(nlogn)。
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
int T,n;
ll a[500005],K;
vector<int>g[500005];
vector<ll>vec[500005];
vector<pair<int,ll>>id[500005];
inline int read() {
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x*f;
}
ll dfs(int u,int topf,ll K){
int m=g[u].size()-(u!=1);if(m==0)return K*a[u];
for(auto x:id[u])if(x.fi==K)return x.se;
vec[u].clear();ll tot=0;
for(auto v:g[u]){
if(v!=topf){
ll x=dfs(v,u,K/m),y=dfs(v,u,K/m+1);
tot+=x,vec[u].pb(y-x);
}
}sort(vec[u].begin(),vec[u].end()),reverse(vec[u].begin(),vec[u].end());
for(int j=0;j<K-K/m*m;j++)tot+=vec[u][j];
id[u].pb(make_pair(K,tot+K*a[u]));
return tot+K*a[u];
}
int main(){
freopen("crossroad.in","r",stdin);
freopen("crossroad.out","w",stdout);
T=read();
while(T--){
n=read(),K=read();for(int i=1;i<=n;i++)a[i]=read(),g[i].clear(),id[i].clear();
for(int i=1;i<n;i++){
int u=read(),v=read();g[u].pb(v),g[v].pb(u);
}printf("%lld\n",dfs(1,0,K));
}
}
B. 鹿角虫道
原题为「Gym102331C」Counting Cactus
姑且称之为仙人掌计数。
令 f ( u , S ) f(u,S) f(u,S)表示 u u u号节点为根,节点集合为 S S S的方案数。
令 g ( u , S ) g(u,S) g(u,S)表示 u u u号节点为根,且 u u u恰好只在一个环上,节点集合为 S S S的方案数。
令 d p ( u , v , S ) dp(u,v,S) dp(u,v,S)为钦定一个当前环的开头是 u u u,环尾扩展到了 v v v,节点集合为 S S S的方案数。
转移方程为:
1.1
1.1
1.1 设
v
v
v为编号最小的节点,并且
v
∈
T
v\in T
v∈T,
(
f
v
,
T
+
g
u
,
T
+
{
u
}
)
×
f
u
,
S
−
T
→
f
u
,
S
(f_{v,T}+g_{u,T+\{u\}})\times f_{u,S-T}\to f_{u,S}
(fv,T+gu,T+{u})×fu,S−T→fu,S
1.2
1.2
1.2 若
u
u
u在环上,且环的终点为
v
v
v,
(
u
,
x
)
∈
E
(u,x)\in E
(u,x)∈E,
d
p
x
,
v
,
S
−
{
u
}
→
f
u
,
S
,
g
u
,
S
dp_{x,v,S-\{u\}}\to f_{u,S},g_{u,S}
dpx,v,S−{u}→fu,S,gu,S
1.3
1.3
1.3 对于
u
→
v
u\to v
u→v的链,在
u
u
u上挂一个仙人掌,满足
(
u
,
x
)
∈
E
(u,x)\in E
(u,x)∈E,
u
∈
T
u\in T
u∈T,
x
,
v
∉
T
x,v\notin T
x,v∈/T,
d
p
x
,
v
,
S
−
T
×
f
u
,
T
→
d
p
u
,
v
,
S
dp_{x,v,S-T}\times f_{u,T}\to dp_{u,v,S}
dpx,v,S−T×fu,T→dpu,v,S
注意环有顺逆时针两种情况,所以要 / 2 /2 /2。
复杂度 O ( 3 n n 3 ) O(3^nn^3) O(3nn3)。上界很松。通过固定转移系数 f u , T f_{u,T} fu,T可以优化至 O ( 3 n n 2 ) O(3^nn^2) O(3nn2)。
有更好的方法,但是我不会。
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
const int mod=998244353;
int n,m,a[13][13];
ll inv2,f[13][1<<13],dp[13][13][1<<13],g[13][1<<13],res;
void add(ll &x,ll y){
x=(x+y)%mod;
}
ll fpow(ll x,ll y){
ll z(1);
for(;y;y>>=1){
if(y&1)z=z*x%mod;
x=x*x%mod;
}return z;
}
int main(){
freopen("stag.in","r",stdin);
freopen("stag.out","w",stdout);
cin>>n>>m,inv2=fpow(2,mod-2);for(int i=1;i<=m;i++){
int u,v;cin>>u>>v,u--,v--,a[u][v]=a[v][u]=1;
}for(int i=0;i<n;i++)f[i][0]=1;
for(int s=1;s<1<<n;s++){
for(int i=0;i<n;i++){
if(s>>i&1) {
for(int j=0;j<n;j++){
if(i==j||!(s>>j&1))continue;
for(int k=0;k<n;k++){
if(i==j||j==k||!(s>>k&1)||!a[i][k])continue;
for(int s2=s-(1<<j)-(1<<k);s2;s2=(s2-1)&(s-(1<<j)-(1<<k))){
if(s2>>i&1)add(dp[i][j][s],dp[k][j][s-s2]*f[i][s2-(1<<i)]);
}
}
if(a[i][j]){
for(int s2=s-(1<<j);s2;s2=(s2-1)&(s-(1<<j))){
if(s2>>i&1)add(dp[i][j][s],f[i][s2-(1<<i)]*f[j][s-s2-(1<<j)]);
}
}
}
}
}
for(int i=0;i<n;i++){
if(!(s>>i&1)){
int j=0;while(!(s>>j&1))j++;
for(int s2=s;s2;s2=(s2-1)&s){
if(!(s2>>j&1))continue;
add(f[i][s],g[i][s2]*f[i][s-s2]);
for(int k=0;k<n;k++){
if((s2>>k&1)&&a[i][k]){
add(f[i][s],f[j][s2-(1<<j)]*f[i][s-s2]);
}
}
}
for(int j=0;j<n;j++){
if(i==j||!(s>>j&1)||!a[i][j])continue;
for(int k=0;k<n;k++){
if(i==k||j==k||!(s>>k&1)||!a[i][k])continue;
add(f[i][s],dp[k][j][s]*inv2);
add(g[i][s],dp[k][j][s]*inv2);
}
}
}
}
}
cout<<f[0][(1<<n)-2];
}
C. 泪水之城
神秘多项式。。。
D. 生命血
应该可以看出来这是一个拟阵。
不妨将其转化为二分图匹配,使用 hall \text{hall} hall定理,只需关注右部点中的一段连续区间。问题转述为,对于任意 1 ≤ i ≤ j ≤ m 1\le i\le j\le m 1≤i≤j≤m, s r j − s l i − 1 ≥ j − i + 1 s_{r_j}-s_{l_i-1}\ge j-i+1 srj−sli−1≥j−i+1,其中 s i s_i si表示 a i a_i ai的前缀和。
不妨将话说明白些。分参易得 s r j − j ≥ s l i − 1 − i + 1 s_{r_j}-j\ge s_{l_i-1}-i+1 srj−j≥sli−1−i+1。
我们将其视作位置 i i i的排名 f i f_i fi, g i g_i gi。那么对于任意 j ≥ i j\ge i j≥i有 f j ≥ g i f_j\ge g_i fj≥gi。每次插入一个操作只会影响 i i i, j j j(相对位置),因此前面的排名不变,设插入位置为 k k k,只需判断 max i = 1 k g i \max_{i=1}^k g_i maxi=1kgi与 min i = k m f i \min_{i=k}^mf_i mini=kmfi的大小关系,因此用两颗线段树维护。
复杂度 O ( n log n ) O(n\log n) O(nlogn)。
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define int ll
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
int n,m,T,L[300005],R[300005],a[300005],s[300005],bit[300005];
struct node{
int dat,max,min;
}t[300005*4];
struct node2{
int v,l,r,id;
bool operator <(const node2 &a)const{
return v>a.v;
}
}q[300005];
vector<int>vec;
void add(int x,int k){
for(;x<=m;x+=x&-x)bit[x]+=k;
}
int ask(int x){
int tot(0);for(;x;x-=x&-x)tot+=bit[x];return tot;
}
void pushup(int p){
t[p].max=max(t[p<<1].max,t[p<<1|1].max);
t[p].min=min(t[p<<1].min,t[p<<1|1].min);
}
void dat(int p,int x){
t[p].max+=x,t[p].min+=x,t[p].dat+=x;
}
void pushdown(int p){
if(t[p].dat)dat(p<<1,t[p].dat),dat(p<<1|1,t[p].dat),t[p].dat=0;
}
void build(int p,int l,int r){
t[p].dat=0;t[p].min=inf,t[p].max=-inf;
if(l==r)return;
int mid=l+r>>1;build(p<<1,l,mid),build(p<<1|1,mid+1,r);
}
void mdy(int p,int l,int r,int x,int y,int z){
if(l==r){t[p].min=y,t[p].max=z;return;}
pushdown(p);int mid=l+r>>1;
x<=mid?mdy(p<<1,l,mid,x,y,z):mdy(p<<1|1,mid+1,r,x,y,z);
pushup(p);
}
void upd(int p,int l,int r,int ql,int qr,int x){
if(ql>qr)return;
if(ql<=l&&r<=qr){dat(p,x);return;}
pushdown(p);int mid=l+r>>1;
if(ql<=mid)upd(p<<1,l,mid,ql,qr,x);if(mid<qr)upd(p<<1|1,mid+1,r,ql,qr,x);
pushup(p);
}
int qry(int p,int l,int r,int ql,int qr,int op){
if(ql>qr)return op?-inf:inf;
if(ql<=l&&r<=qr)return op?t[p].max:t[p].min;
pushdown(p);int mid=l+r>>1;
if(qr<=mid)return qry(p<<1,l,mid,ql,qr,op);
if(mid<ql)return qry(p<<1|1,mid+1,r,ql,qr,op);
if(op==0)return min(qry(p<<1,l,mid,ql,qr,op),qry(p<<1|1,mid+1,r,ql,qr,op));
return max(qry(p<<1,l,mid,ql,qr,op),qry(p<<1|1,mid+1,r,ql,qr,op));
}
signed main(){
freopen("lifeblood.in","r",stdin);
freopen("lifeblood.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i],s[i]=s[i-1]+a[i];
for(int i=1;i<=m;i++){
int l,r,v;cin>>l>>r>>v;
q[i]={v,l,r,i},L[i]=l,R[i]=r;
}sort(q+1,q+1+m);
vec.clear();ll res=0;build(1,1,m);for(int i=1;i<=m;i++)bit[i]=0;
for(int i=1;i<=m;i++){
int l=q[i].l,r=q[i].r,k=q[i].id;
mdy(1,1,m,k,s[r]-ask(k),s[l-1]-ask(k)+1);
upd(1,1,m,k+1,m,-1);
if(qry(1,1,m,1,k,1)>qry(1,1,m,k,m,0)){
mdy(1,1,m,k,inf,-inf),upd(1,1,m,k+1,m,1);
}
else {
vec.pb(k),res+=q[i].v,add(k,1);
}
}cout<<res<<"\n"<<vec.size()<<"\n";
if(vec.size()){
for(int i=0;i<vec.size()-1;i++){
cout<<vec[i]<<' ';
}cout<<vec.back();
cout<<"\n";
}
}
}