8.10模拟赛
T1 方案统计
题目大意:
给出一棵n个节点的无根树,其中m个节点是特殊节点,求对于任意0<=i<=m,包含i个特殊节点的联通块个数
思路:
树形dp
dp i j表示以i为根的子树 包含j个特殊节点的联通块个数
转移就是枚举该节点任意两个子树 dp i j+k += dp to[i] j * dp i k 从大到小枚举避免重复计算
1 #include<iostream> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #define MAXN 1100 11 #define ll long long 12 #define inf 2139062143 13 #define MOD 998244353 14 using namespace std; 15 inline int read() 16 { 17 int x=0,f=1;char ch=getchar(); 18 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 19 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 20 return x*f; 21 } 22 int n,m,g[MAXN],fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],cnt; 23 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 24 ll sz[MAXN],dp[MAXN][MAXN],ans[MAXN]; 25 void dfs(int x,int fa) 26 { 27 sz[x]=g[x],dp[x][sz[x]]=1,ans[sz[x]]++; 28 for(int i=fst[x];i;i=nxt[i]) 29 if(to[i]!=fa) 30 { 31 dfs(to[i],x); 32 for(int j=sz[x];j>=g[x];j--) 33 for(int k=sz[to[i]];k>=0;k--) 34 (ans[j+k]+=dp[to[i]][k]*dp[x][j]%MOD)%=MOD,(dp[x][j+k]+=dp[to[i]][k]*dp[x][j]%MOD)%=MOD; 35 sz[x]+=sz[to[i]]; 36 } 37 } 38 int main() 39 { 40 freopen("tree.in","r",stdin); 41 freopen("tree.out","w",stdout); 42 n=read(),m=read();int a,b; 43 for(int i=1;i<=m;i++) g[read()]=1; 44 for(int i=1;i<n;i++) {a=read(),b=read();add(a,b);add(b,a);} 45 dfs(1,0); 46 for(int i=0;i<=m;i++) printf("%lld ",ans[i]); 47 }
T2 机器人装配
题目大意:
有n个机器人和m个配件,每个机器人需要若干个的配件
每个机器人对每个配件都有一定适配度
求每个机器人分配其所需数量的配件,所有机器人对其分配到的配件的适配度之和最大是多少
思路:
建立费用流模型
源点向机器人连流量为所需配件数,费用为0的边
机器人向配件连流量为1,费用为适配度的边
配件向汇点连流量为1,费用为0的边
1 #include<iostream> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #define MAXN 310 11 #define MAXM 30100 12 #define ll long long 13 #define inf 2139062143 14 using namespace std; 15 inline int read() 16 { 17 int x=0,f=1;char ch=getchar(); 18 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 19 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 20 return x*f; 21 } 22 int n,m,ans; 23 struct ZKW 24 { 25 int fst[MAXN],to[MAXM<<1],nxt[MAXM<<1],val[MAXM<<1],cos[MAXM<<1],cnt; 26 int dis[MAXN],s,t,vis[MAXN]; 27 ZKW() {ans=0,cnt=2;} 28 void add(int u,int v,int w,int c) {nxt[cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w,cos[cnt++]=c;} 29 int spfa() 30 { 31 memset(dis,127,sizeof(dis)); 32 queue<int> q; 33 dis[t]=0,vis[t]=1;q.push(t); 34 while(!q.empty()) 35 { 36 int x=q.front();q.pop();vis[x]=0; 37 for(int i=fst[x];i;i=nxt[i]) 38 if(val[i^1]&&dis[to[i]]>dis[x]-cos[i]) 39 { 40 dis[to[i]]=dis[x]-cos[i]; 41 if(!vis[to[i]]) {q.push(to[i]);vis[to[i]]=1;} 42 } 43 } 44 memset(vis,0,sizeof(vis)); 45 return dis[s]!=inf; 46 } 47 int dfs(int x,int a) 48 { 49 if(x==t||!a) {ans+=dis[s]*a;return a;} 50 if(vis[x]) return 0; 51 vis[x]=1;int res=0,f; 52 for(int i=fst[x];i&&a;i=nxt[i]) 53 if(dis[to[i]]==dis[x]-cos[i]&&(f=dfs(to[i],min(a,val[i])))) 54 res+=f,val[i]-=f,val[i^1]+=f,a-=f; 55 vis[x]=0; 56 return res; 57 } 58 void solve(){while(spfa()) dfs(s,inf+30);} 59 }Z; 60 int main() 61 { 62 freopen("robot.in","r",stdin); 63 freopen("robot.out","w",stdout); 64 n=read(),m=read();int a,b,c,d; 65 Z.s=n+m+1,Z.t=n+m+2; 66 for(int i=1;i<=n;i++) {c=read();Z.add(Z.s,i,c,0);Z.add(i,Z.s,0,0);} 67 for(int i=1;i<=n;i++) 68 for(int j=1;j<=m;j++) {c=read();Z.add(i,n+j,1,-c);Z.add(n+j,i,0,c);} 69 for(int i=1;i<=m;i++) {Z.add(i+n,Z.t,1,0);Z.add(Z.t,i+n,0,0);} 70 Z.solve();printf("%d",-ans); 71 }
T3 区间选点
题目大意:
数轴上n个点,坐标分别为x i 选出编号连续的一些点,使得被选出的所有点到某一点的距离和的最小值不超过m ,问最多选出多少点
思路:
首先可以想到滑动窗口来维护这个区间
发现权值线段树可以解决掉区间中位数 再维护一下区间内坐标之和
用中位数*左边数量-左边坐标和+右边坐标和-中位数*右边数量
1 #include<iostream> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #define MAXN 100100 11 #define MAXX 1001000 12 #define ll long long 13 #define inf 2139062143 14 using namespace std; 15 inline int read() 16 { 17 int x=0,f=1;char ch=getchar(); 18 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 19 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 20 return x*f; 21 } 22 int n,m,l,ans,g[MAXN],val[MAXX<<2],maxn; 23 ll sum[MAXX<<2]; 24 void mdf(int k,int l,int r,int x,int p) 25 { 26 if(l==r) {sum[k]+=p*x,val[k]+=p;return ;} 27 int mid=(l+r)>>1; 28 if(x<=mid) mdf(k<<1,l,mid,x,p); 29 else mdf(k<<1|1,mid+1,r,x,p); 30 sum[k]=sum[k<<1]+sum[k<<1|1],val[k]=val[k<<1]+val[k<<1|1]; 31 } 32 ll Ask(int k,int l,int r,int x) 33 { 34 if(l==r) return val[k]*maxn+l; 35 int mid=(l+r)>>1; 36 if(val[k<<1]>=x) return Ask(k<<1,l,mid,x); 37 else return Ask(k<<1|1,mid+1,r,x-val[k<<1]); 38 } 39 ll query(int k,int l,int r,int a,int b) 40 { 41 if(a>b) return 0; 42 if(l==a&&r==b) return sum[k]; 43 int mid=(l+r)>>1; 44 if(b<=mid) return query(k<<1,l,mid,a,b); 45 else if(a>mid) return query(k<<1|1,mid+1,r,a,b); 46 else return query(k<<1,l,mid,a,mid)+query(k<<1|1,mid+1,r,mid+1,b); 47 } 48 int lft(int k,int l,int r,int a,int b) 49 { 50 if(a>b) return 0; 51 if(l==a&&r==b) return val[k]; 52 int mid=(l+r)>>1; 53 if(b<=mid) return lft(k<<1,l,mid,a,b); 54 else if(a>mid) return lft(k<<1|1,mid+1,r,a,b); 55 else return lft(k<<1,l,mid,a,mid)+lft(k<<1|1,mid+1,r,mid+1,b); 56 } 57 ll calc(int x) 58 { 59 if(x==l) return 0; 60 if(x-l==1) return abs(g[x]-g[l]); 61 ll t=(x-l+1)/2+1,k=Ask(1,1,maxn,t),lv=lft(1,1,maxn,1,k%maxn-1),q= k/maxn+2*lv-x+l-1;k%=maxn; 62 return query(1,1,maxn,k+1,maxn)-query(1,1,maxn,1,k-1)+q*k; 63 } 64 int main() 65 { 66 freopen("choose.in","r",stdin); 67 freopen("choose.out","w",stdout); 68 n=read(),m=read(); 69 for(int i=1;i<=n;i++) g[i]=read(),maxn=max(maxn,g[i]); 70 for(int i=l=1;i<=n;i++) 71 { 72 mdf(1,1,maxn,g[i],1); 73 while(calc(i)>m) {mdf(1,1,maxn,g[l],-1);l++;} 74 ans=max(ans,i-l+1); 75 } 76 printf("%d",ans); 77 }