自闭了
A
所有的(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
",ans);
return 0;
}
B
考虑枚举(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;
}
C
两个串相似等价于两个串中B和N的个数是相同的,对某个给定的字符串,用一个二元组((x,y))来刻画其中B和N的个数,注意到(x>0,y>0)时串中一定存在BN或NB,那么((x_1,y_1) o (x_2,y_2))的最少操作次数如下:
[egin{cases}
max(|x_1-x_2|,|y_1-y_2|) & mathrm{sgn}(x1-x2)=mathrm{sgn}(y_1-y_2)\
|x_1-x_2|+|y_1-y_2|& mathrm{sgn}(x1-x2)
eq mathrm{sgn}(y_1-y_2)
end{cases}
]
其中(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
",ans);
chk2(ans);
return 0;
}
D
记(f_{u,0/1})表示已处理完子树(u)的所有边,且(u o 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;
}