【学习笔记】NOIP模拟赛25

据说是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+vfv,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 vT ( 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,STfu,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 uv的链,在 u u u上挂一个仙人掌,满足 ( u , x ) ∈ E (u,x)\in E (u,x)E u ∈ T u\in T uT 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,ST×fu,Tdpu,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. 生命血

原题为 「Gym102268D」Dates

应该可以看出来这是一个拟阵。

不妨将其转化为二分图匹配,使用 hall \text{hall} hall定理,只需关注右部点中的一段连续区间。问题转述为,对于任意 1 ≤ i ≤ j ≤ m 1\le i\le j\le m 1ijm s r j − s l i − 1 ≥ j − i + 1 s_{r_j}-s_{l_i-1}\ge j-i+1 srjsli1ji+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 srjjsli1i+1

我们将其视作位置 i i i的排名 f i f_i fi, g i g_i gi。那么对于任意 j ≥ i j\ge i ji f j ≥ g i f_j\ge g_i fjgi。每次插入一个操作只会影响 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"; } } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530089.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(24)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示