自闭了
所有的\(a_i\)可以根据是否\(\leq m\)分为两类,枚举使用了多少\(\leq m\)的数,\(>m\)的数的个数可以直接算出来。
int n,d,m,m1,m2,a[N],b[N];
ll s1[N],s2[N];
int main()
{
n=read();d=read();m=read();
rep(i,1,n)
{
int x=read();
if (x>m) a[++m1]=x;
else b[++m2]=x;
}
sort(a+1,a+1+m1);sort(b+1,b+1+m2);
reverse(a+1,a+1+m1);reverse(b+1,b+1+m2);
ll ans=0;
rep(i,1,m1) s1[i]=s1[i-1]+a[i];
rep(i,1,m2) s2[i]=s2[i-1]+b[i];
rep(i,0,m2)
{
ll now=s2[i];
int rst=(n-i-1)/(d+1)+1;
//cout << i << " " << rst << endl;
now+=s1[min(rst,m1)];
ans=max(now,ans);
}
printf("%lld\n",ans);
return 0;
}
考虑枚举\(k\)的全排列判断是否合法,注意到一个合法的\(c\)序列应满足选出来的边形成了若干个简单环,即所有点的入度和出度均为1。记\(cant_{i,j,p,q}\)表示当\(c_i=j,c_p=q\)时是否存在某个点的入度或者出度\(>1\).这个数组可以在保证\(c_i=j,c_p=q\)均合法时使用bitset加速判断。
int n,m,k,up,c[10],len[10][10],ans=0;
vector<pii> edge[10][10],sq[N];
bool cant[10][10][10][10],ban[10][10];
bitset<N> in[10][10],out[10][10];
void dfs(int dep,int sum)
{
if (dep>k) {ans+=(sum==n);return;}
rep(i,1,dep)
{
if (ban[dep][i]) continue;
int ok=1;
rep(j,1,dep-1)
{
if (cant[j][c[j]][dep][i]) {ok=0;break;}
}
if (!ok) continue;
c[dep]=i;
dfs(dep+1,sum+len[dep][i]);
}
}
int main()
{
n=read();m=read();k=read();
rep(i,1,m)
{
int u=read()-1,v=read()-1,w=read();
sq[u].pb(mkp(w,v));
}
rep(u,0,n-1)
{
int d=sq[u].size();
sort(sq[u].begin(),sq[u].end());
rep(j,1,d)
{
int v=sq[u][j-1].sec,w=sq[u][j-1].fir;
edge[d][j].pb(mkp(u,v));
}
}
rep(d,1,k) rep(i,1,d)
{
len[d][i]=edge[d][i].size();
rep(j,0,len[d][i]-1)
{
int u=edge[d][i][j].fir,v=edge[d][i][j].sec;
if ((in[d][i][v]) || (out[d][i][u])) {ban[d][i]=1;break;}
in[d][i][v]=1;out[d][i][u]=1;
}
}
rep(d1,1,k) rep(i1,1,d1)
{
if (ban[d1][i1]) continue;
rep(d2,d1+1,k) rep(i2,1,d2)
{
if (ban[d2][i2]) continue;
if (((in[d1][i1]&in[d2][i2]).any()) || ((out[d1][i1]&out[d2][i2]).any())) cant[d1][i1][d2][i2]=1;
}
}
dfs(1,0);
printf("%d",ans);
return 0;
}
两个串相似等价于两个串中B和N的个数是相同的,对某个给定的字符串,用一个二元组\((x,y)\)来刻画其中B和N的个数,注意到\(x>0,y>0\)时串中一定存在BN或NB,那么\((x_1,y_1)\to (x_2,y_2)\)的最少操作次数如下:
其中\(\mathrm{sgn}(x)\)表示x的正负性。
考虑原问题,一个显然的想法是二分一个最大的操作次数mid再判断是否存在一个满足条件的串。check时首先对每个\(x_i,y_i\)都有一个变化区间,如果最后\(\mathrm{sgn}|x‘-x|=\mathrm{sgn}|y‘-y|\),那么\(x‘\)与\(y‘\)的差也会有一个区间的限制。对所有同类的区间求交后可以枚举\(x‘\)的取值,根据y的取值区间和差的取值区间找寻是否有合法的y即可。
int n,x[N],y[N];
char s[N];
int chk(int mid)
{
int xl=0,xr=1e9,yl=0,yr=1e9,mnd=-1e9,mxd=1e9;
rep(i,1,n)
{
xl=max(xl,x[i]-mid);xr=min(xr,x[i]+mid);
yl=max(yl,y[i]-mid);yr=min(yr,y[i]+mid);
mnd=max(mnd,y[i]-x[i]-mid);
mxd=min(mxd,y[i]-x[i]+mid);
}
rep(i,xl,xr)
{
int l=max(yl,i+mnd),r=min(yr,i+mxd);
l=max(0,l);
if ((!i) && (!r)) continue;
if (l<=r) return 1;
}
return 0;
}
void chk2(int mid)
{
int xl=0,xr=1e9,yl=0,yr=1e9,mnd=-1e9,mxd=1e9;
rep(i,1,n)
{
xl=max(xl,x[i]-mid);xr=min(xr,x[i]+mid);
yl=max(yl,y[i]-mid);yr=min(yr,y[i]+mid);
mnd=max(mnd,y[i]-x[i]-mid);
mxd=min(mxd,y[i]-x[i]+mid);
}
rep(i,xl,xr)
{
int l=max(yl,i+mnd),r=min(yr,i+mxd);
l=max(0,l);
if ((!i) && (!r)) continue;
if (l<=r)
{
rep(j,1,i) putchar(‘B‘);
rep(j,1,r) putchar(‘N‘);
return;
}
}
}
int main()
{
n=read();
rep(i,1,n)
{
scanf("%s",s+1);
int m=strlen(s+1);
rep(j,1,m)
{
if (s[j]==‘B‘) x[i]++;else y[i]++;
}
}
int l=0,r=1e9,ans=0;
while (l<=r)
{
int mid=(l+r)>>1;
if (chk(mid)) {ans=mid;r=mid-1;}
else l=mid+1;
}
printf("%d\n",ans);
chk2(ans);
return 0;
}
记\(f_{u,0/1}\)表示已处理完子树\(u\)的所有边,且\(u\to fa_u\)的边是向下/上的最小的t之和。注意到子树的根\(u\)的贡献只与状态的第二维和它儿子中向上走的个数有关,故在当前状态合法时,可以先强制所有边均是从u向下走的,再枚举有几个儿子为向上走(这一部分的\(f_v\)的贡献可以由贪心算出),再尽可能的合并路径后算出\(t_u\)的贡献。
struct node{int to,nxt;}sq[N<<1];
int all=0,head[N];
void addedge(int u,int v)
{
all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all;
}
int n,h[N],t[N];
ll f[N][2];
void dfs(int u,int fu)
{
vl g;g.clear();ll sum=0;
go(u,i)
{
if (v==fu) continue;
dfs(v,u);
sum+=f[v][0];
g.pb(f[v][1]-f[v][0]);
}
sort(g.begin(),g.end());
int m=g.size();ll tmp=sum;
if ((!fu) || (h[u]<=h[fu]))
{
f[u][0]=tmp+1ll*t[u]*max(m,1);
rep(i,1,m)
{
tmp+=g[i-1];
f[u][0]=min(f[u][0],tmp+1ll*t[u]*max(m-i,i+(fu>0)));
}
}
else f[u][0]=1e12;
tmp=sum;
if ((!fu) || (h[u]>=h[fu]))
{
f[u][1]=tmp+1ll*t[u]*(m+(fu>0));
rep(i,1,m)
{
tmp+=g[i-1];
f[u][1]=min(f[u][1],tmp+1ll*t[u]*max(m-i+(fu>0),i));
}
}
else f[u][1]=1e12;
}
int main()
{
n=read();
rep(i,1,n) t[i]=read();
rep(i,1,n) h[i]=read();
rep(i,1,n-1)
{
int u=read(),v=read();
addedge(u,v);addedge(v,u);
}
dfs(1,0);
printf("%lld",min(f[1][0],f[1][1]));
return 0;
}
Codeforces Round #664 (Div. 1) 部分简要题解
原文:https://www.cnblogs.com/encodetalker/p/13495771.html