2019-11-9

Posted mendessy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019-11-9相关的知识,希望对你有一定的参考价值。

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
"):printf("No
");
    }
    return 0;
}

以上是关于2019-11-9的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序代码片段

VSCode自定义代码片段——CSS选择器

谷歌浏览器调试jsp 引入代码片段,如何调试代码片段中的js

片段和活动之间的核心区别是啥?哪些代码可以写成片段?

VSCode自定义代码片段——.vue文件的模板

VSCode自定义代码片段6——CSS选择器