T1
大水题,Skip。
T2 将军令
树,一个点驻队可以控制距离小于等于k的点,求控制所有点的最小驻队数。n<=100000,k<=20
贪心解法:
- 按深度从大到小排序,拿出最深的一个,如果没有被控制就找k级祖先然后暴力遍历,复杂度O(nk)
- 维护两个值:下面的驻队点到当前点还能延伸的距离,下面未被控制的点的最深深度,贪心放点。复杂度O(n)
DP解法:
- f [ u ] [ j ] f[u][j] f[u][j], j > 0 j>0 j>0表示向上至少还能控制的距离, j < 0 j<0 j<0表示向下至多还有深度之差为多少的点需要控制,转移比较麻烦。
我写的O(n)贪心。
Code:
#include<bits/stdc++.h>
#define LL long long
#define maxn 100005
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
template<class T>inline void write(T x){
if(x>=10) write(x/10);
putchar(x%10+48);
}
int n,K,type,ans,mxd[maxn],up[maxn];
vector<int>G[maxn];
void dfs(int u,int ff){
up[u]=-1;
for(int i=G[u].size()-1,v;i>=0;i--) if((v=G[u][i])!=ff){
dfs(v,u);
up[u]=max(up[u],up[v]-1);
mxd[u]=max(mxd[u],mxd[v]+1);
}
if(up[u]>=mxd[u]) mxd[u]=-1;
else if(mxd[u]==K||u==1) ans++,mxd[u]=-1,up[u]=K;
}
int main()
{
read(n),read(K),read(type);
for(int i=1,x,y;i<n;i++) read(x),read(y),G[x].push_back(y),G[y].push_back(x);
dfs(1,0);
write(ans),putchar('\n');
}
T3
长度小于等于40000的01序列,小于等于8个为1,可以翻转给定长度的区间(种数小于等于64),问最少翻转次数。
区间转化为差分,翻转相当于改两个点,小于等于16个1,bfs预处理翻转每一对1需要的最少次数,状压转移即可。
这篇题解值得一看。
Code:
#include<bits/stdc++.h>
#define maxn 40005
#define maxm 65
#define maxk 18
using namespace std;
const int inf = 0x3f3f3f3f;
int n,m,k,a[maxk],b[maxm],dis[maxn],d[maxk][maxk],f[1<<maxk];
bool arr[maxn];
queue<int>q;
void bfs(int S){
memset(dis,0x3f,sizeof dis);
dis[S]=0,q.push(S);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=1;i<=m;i++){
if(u+b[i]<=n+1&&dis[u+b[i]]==inf) dis[u+b[i]]=dis[u]+1,q.push(u+b[i]);
if(u-b[i]>=1&&dis[u-b[i]]==inf) dis[u-b[i]]=dis[u]+1,q.push(u-b[i]);
}
}
}
int main()
{
scanf("%d%d%d",&n,&k,&m);
for(int i=1,x;i<=k;i++) scanf("%d",&x),arr[x]^=1,arr[x+1]^=1;
for(int i=1;i<=m;i++) scanf("%d",&b[i]);
k=0;
for(int i=1;i<=n+1;i++) if(arr[i]) a[k++]=i;
for(int i=0;i<k-1;i++){
bfs(a[i]);
for(int j=i+1;j<k;j++) d[i][j]=dis[a[j]];
}
memset(f,0x3f,sizeof f);
f[0]=0;
for(int s=1,low;s<1<<k;s++) {
for(int i=0;;i++) if(s>>i&1) {low=i;break;}
for(int i=low+1;i<k;i++) if(s>>i&1) f[s]=min(f[s],f[s^(1<<i)^(1<<low)]+d[low][i]);
}
printf("%d\n",f[(1<<k)-1]);
}