T1
显然,对于一个城堡,要么就不放兵,要么就放到\(2*a_i+1\)
然后对于一个城堡,我们首先将对手放兵从小到大排序,然后就是一个分组背包(每一组只能选1个)的问题了QAQ 复杂度\(O(nms)\) 因为跑不满上界,所以过得了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=1100;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int s,n,m;
int f[maxn][20010];
int dp[20010],qaq[maxn];
int arr[maxn][maxn],arrr[maxn][maxn],val[maxn][maxn];
int main(){
freopen("arrange.in","r",stdin);
freopen("arrange.out","w",stdout);
s=read();n=read();m=read();
for(int i=1;i<=s;i++)
for(int j=1,x;j<=n;j++)
x=read(),arr[i][j]=x*2+1;
if(s==1){
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++)
f[i][j]=f[i-1][j];
for(int j=arr[1][i];j<=m;j++){
f[i][j]=max(f[i][j],f[i-1][j-arr[1][i]]+i);
}
}
printf("%d",f[n][m]);
}
else{
memset(dp,0xcf,sizeof(dp));
dp[0]=0;
for(int i=1;i<=s;i++)
for(int j=1;j<=n;j++)
arrr[j][i]=arr[i][j];
for(int i=1;i<=n;i++)
sort(arrr[i]+1,arrr[i]+1+s);
for(int i=1;i<=n;i++){
for(int j=m;j>=0;j--){
for(int k=1;k<=s;k++){
if(j>=arrr[i][k])
dp[j]=max(dp[j],dp[j-arrr[i][k]]+(i)*(k));
}
}
}
int ans=0;
for(int i=0;i<=m;i++) ans=max(ans,dp[i]);
printf("%d",ans);
}
return 0;
}
T2
这道题通过题目可以分析出来:父亲与其所有的后代权值的差绝对值\(\le k\) 。我们考虑先找一个根节点:显然根节点与除了自己的所有节点的权值差绝对值\(\le k\) 找到根节点之后,我们把根节点抛开不管,显然根节点的左子树在中序遍历中一定在根节点的左边,右子树在中序遍历中一定在根节点的右边,然后将根节点的左子树,右子树(看做独立的树) 进行同样的操作,最后就可以构成符合条件的树,如何不能构成,就返回\(false\)
如何做思路就很明了了
\(solve(l,r)\) 表示当前处理到中序遍历的\([l,r]\)了,然后在这个区间从左向右扫一遍,找到一个满足条件的\(i\)使得\(a[i]+k>=maxx \&\& a[i]-k<=maxx\) 然后继续递归\(solve(l,i-1),solve(i+1,r)\)
但是显然这样做肯定是\(O(n^2)\)的 过不了。 然而玄学的启发式合并可以将这道题的复杂度转换为\(O(nlogn)\),我不会证。 启发式合并就是从当前枚举的左右区间同时向中间扫 即在第i步的时候判断\(l+i,r-i\) 对应的数是否是满足条件的。如果满足条件就可以直接递归下去。 至于为什么启发式合并要快一点,因为同时从左边,右边向中间扫,而如果扫到了就可以直接递归下去。相当于可以通过一个小的区间,确定一个大的区间,复杂度自然就下去了
还有就是注意ST表维护区间最大最小值的细节QAQ
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=2e5+10;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int t,n,k,a[maxn],lg[maxn],stmin[30][maxn],stmax[30][maxn];
int getmin(int l,int r){
int k=lg[r-l+1];
return min(stmin[k][l],stmin[k][r-(1<<k)+1]);
}
int getmax(int l,int r){
int k=lg[r-l+1];
return max(stmax[k][l],stmax[k][r-(1<<k)+1]);
}
bool solve(int l,int r){
if(l>=r) return true;
int minn=getmin(l,r),maxx=getmax(l,r);
int i=0;
for(;i+l<=r-i;i++){
if(a[i+l]-k<=minn && a[i+l]+k>=maxx){
return solve(l,l+i-1) && solve(l+i+1,r);
}
if(a[r-i]-k<=minn && a[r-i]+k>=maxx){
return solve(l,r-i-1) && solve(r-i+1,r);
}
}
return false;
}
int main(){
freopen("tree2.in","r",stdin);
freopen("tree.out","w",stdout);
t=read();
while(t--){
n=read();k=read();
lg[0]=-1;
for(int i=1;i<=n;i++){
a[i]=read();
lg[i]=lg[i>>1]+1;
stmin[0][i]=a[i];stmax[0][i]=a[i];
}
for(int i=1;i<=lg[n];i++)
for(int j=1;j+(1<<i)-1<=n;j++){
stmin[i][j]=min(stmin[i-1][j],stmin[i-1][j+(1<<(i-1))]);
stmax[i][j]=max(stmax[i-1][j],stmax[i-1][j+(1<<(i-1))]);
}
solve(1,n)?printf("Yes\n"):printf("No\n");
}
return 0;
}