8.9模拟赛

A组

T1.dostavljac 餐馆

树形DP,怎么处理走回来呢?考场想了f[i][j][0/1]表示以i为根子树,用了j秒,并且选/不选当前点,不能转移,为什么呢?因为这个第三维完全没用,可以在一开始就考虑。

正解f[i][j][0/1]表示以i为根的子树,用了j秒,并且回到/不回到当前点,这样就可以分类转移了。

转移时考虑做到子树v,分三类讨论。

注意一个点只能选一次,倒序循环。

#include<iostream>
#include<cstdio>

using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=1005;

struct Edge{
    int next,to;
}e[MAXN];
int ecnt,head[MAXN],ind[MAXN];
inline void add(int x,int y){
    e[++ecnt].next = head[x];
    e[ecnt].to = y;
    head[x] = ecnt;
}

int n,m;

int f[MAXN][MAXN*2][2];
int a[MAXN];

int ans=0;
 

void dfs(int x,int pre){
    f[x][1][0]=f[x][1][1]=a[x];
    int tmp=0,mx=0;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(v==pre) continue;
        dfs(v,x);
        for(int j=m;j>=0;j--){
            for(int k=m-j-1;k>=0;k--){
                f[x][j+k+2][0]=max(f[x][j+k+2][0],f[x][j][0]+f[v][k][0]);
                f[x][j+k+2][1]=max(f[x][j+k+2][1],f[x][j][1]+f[v][k][0]);
                f[x][j+k+1][1]=max(f[x][j+k+1][1],f[x][j][0]+f[v][k][1]);
            }
        }
    }
}

void solve(){
    dfs(1,0);
    cout<<max(f[1][m][1],f[1][m][0]);
}

int main(){
    freopen("dostavljac.in","r",stdin);
    freopen("dostavljac.out","w",stdout);
    n=rd();m=rd();
    int x,y;
    for(int i=1;i<=n;i++) a[i]=rd();
    for(int i=1;i<=n-1;i++){
        x=rd();y=rd();
        add(x,y);add(y,x);
    }
    solve();
    return 0;
}
View Code

 T2.range 区间

分块维护块内前缀后缀积,块大小为k正好满足。

被一般套路限制了,这个分块不需要真的开新数组存,那样空间是n^2的(用vector可以少一些,但依旧很大)

正解是直接在原位置上维护这个位置在块内的前缀后缀,这样就可以啦。

这题卡空间(差评)

#include<iostream>
#include<cstdio>
#include<vector>
//#define int long long
using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=20000005;

int n,m,mod;
int A,B,C,D;
int a[MAXN];

int num;
int pre[MAXN],lst[MAXN];

#define l(x) ((((x)-1)*m)+1)
#define r(x) ((x)==num?n:((x)*m))
#define bl(x) ((((x)-1)/m)+1)

signed main(){
    freopen("range.in","r",stdin);
    freopen("range.out","w",stdout);
    n=rd();m=rd();mod=rd();
    A=rd();B=rd();C=rd();D=rd();
    a[1]=A;
    long long tmp;
    for(int i=2;i<=n;i++) {
        tmp=1ll*(a[i-1]*1ll*B+C)%D;
        a[i]=(int) tmp; 
    }
    num=n/m;if(n%m)num++;
    
    for(int i=1;i<=num;i++){
        int L=l(i),R=r(i);
        pre[L]=a[L];
        for(int j=L+1;j<=R;j++){
            tmp=(pre[j-1]*1ll*a[j])%mod;
            pre[j]=(int)tmp;
        }
        lst[R]=a[R];
        for(int j=R-1;j>=L;j--){
            tmp=1ll*(lst[j+1]*1ll*a[j])%mod;
            lst[j]=(int)tmp;
        }
    }
    int ans=0;
    for(int i=1;i<=n-m+1;i++){
        int j=i+m-1;
        if(bl(i)==bl(j)){ans^=pre[r(bl(i))];continue;}
        tmp=1ll*(lst[i]*1ll*pre[j])%mod;
        ans^=(int)tmp;
    }
    cout<<ans;
    return 0;
}
View Code

 

posted @ 2018-08-09 20:46  GhostCai  阅读(103)  评论(0编辑  收藏  举报