20190811 NOIP模拟测试17 「入阵曲 · 将军令 · 星空 」

T1 入阵曲

  将二维压成一维来做,维护每一列的前缀和,n^2枚举最上一行和最下一行,把中间这几行当成一行来做,维护一个桶记录这几行前几列的和的余数是x的个数,因为在模K意义下余数相同的两个数的差是K的倍数 时间复杂度 O(n^3)

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,K,a[410][410],sum[410][410],tmp[1100000],p[1100000];
inline int read(){
    register int ret;
    register char r;
    while(r=getchar(),r<'0'||r>'9');
    ret=r^48;
    while(r=getchar(),r>='0'&&r<='9') ret=(ret<<1)+(ret<<3)+(r^48);
    return ret;
}
int main(){
    n=read(),m=read(),K=read();
    for(register int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=read(),
            sum[i][j]=(sum[i-1][j]+a[i][j])%K;//维护第j列前缀和
    long long ans=0;
    for(register int i=1;i<=n;i++){
        for(register int j=i;j<=n;j++){
            int cet=0;
            for(register int l=1;l<=m;l++){
                cet=((cet+sum[j][l]-sum[i-1][l])%K+K)%K;
                ans+=tmp[cet]++;
                if(cet==0) ans++;
                if(tmp[cet]==1) p[++p[0]]=cet;
            }
            for(int l=1;l<=p[0];l++) tmp[p[l]]=0;
            p[0]=0;
        }
    }
    printf("%lld
",ans);
}
View Code

T2 将军令

  可以想到像 小胖守皇宫 那样的树上DP ,k==1的情况可以做,k==2的情况也可以YY掉,但是K==3或20的情况就不好YY了(但是听说洛谷上有写DP 通式的,码量很小)

  正解是贪心,无根树变有根树,DFS 一遍,用大根堆维护深度最深的点,从该点向上找距他为K的点(如果距离小于K就走到了根,那就用根就行了),然后从这个点在整棵树上找距他小于等于K的点,以后从堆里拿出标记的点直接跳即可。 注意在标记的时候,千万不要碰到一个标记过的点就return,有可能这个点的儿子没有被覆盖,而当前驻扎小队的点会覆盖它的儿子

  PS :这样会TLE 95 ,可以记录如果一个点的所有子孙都被覆盖了(标记过),在开一个数组,把该点标记,这种点是可以跳的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int n,d,t,tot;
int to[210000],head[110000],nex[210000],fa[210000],v[210000],al[210000];
struct node{
    int dep,id;
    bool operator < (node b)const{
        return dep<b.dep;
    }
    node(int a,int b){id=a,dep=b;}
};
priority_queue<node>q;
void add(int x,int y){
    to[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
void dfs(int x,int pre,int dis){
    q.push(node(x,dis+1));
    fa[x]=pre;
    for(int i=head[x];i;i=nex[i]){
        int y=to[i];
        if(y==pre) continue;
        dfs(y,x,dis+1);
    }
}
void work(int x,int k){
    v[x]=1;
    if(nex[head[x]]==0){
        if(to[head[x]]==fa[x]||al[to[head[x]]]) al[x]=1;
    }
    if(k==0) return;
    for(int i=head[x];i;i=nex[i]){
        int y=to[i];
        if(al[y]) continue;//避免重复,陷入死循环
        work(y,k-1);//走儿子的同时,也能走到爸爸
    }
    for(int i=head[x];i;i=nex[i]){
        int y=to[i];
        if(y==fa[x]) continue;
        al[x]=min(al[y],al[x]);
    }
}
int main(){
    scanf("%d%d%d",&n,&d,&t);
    for(int i=1,x,y;i<n;i++){
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(1,0,0);
    int ans=0;
    while(q.size()){
        int w=q.top().id;
        q.pop();
        if(v[w]) continue;
        for(int i=1;i<=d&&w!=1;i++,w=fa[w]);
        ans++;
        work(w,d);
    }
    printf("%d
",ans);
}
View Code

T3 星空

   https://www.luogu.org/problemnew/solution/P3943

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n,K,m,num;
int a[41000],b[70],c[20],v[41000],dis[20][41000],inq[41000],f[1<<17],to[1<<17];
void Dijistra(){
    memset(dis,0x3f,sizeof(dis));
    queue<int>q;
    for(int w=1;w<=num;w++){
        q.push(c[w]);
        inq[c[w]]=1;
        dis[w][c[w]]=0;
        while(q.size()){
            int x=q.front();
            inq[x]=0;
            q.pop();
            for(int i=1;i<=m;i++){
                int y=x-b[i];
                if(y>0&&dis[w][y]>dis[w][x]+1){
                    dis[w][y]=dis[w][x]+1;
                    if(!inq[y]){
                        q.push(y);
                        inq[y]=1;
                    }
                }
                y=x+b[i];
                if(y<=n&&dis[w][y]>dis[w][x]+1){
                    dis[w][y]=dis[w][x]+1;
                    if(!inq[y]){
                        q.push(y);
                        inq[y]=1;
                    }
                }
            }
        }
    }
}
int main(){
    scanf("%d%d%d",&n,&K,&m);
    n++;
    for(int i=1,x;i<=K;i++){
        scanf("%d",&x);
        a[x]^=1,a[x+1]^=1;
    }
    for(int i=1;i<=m;i++){
        scanf("%d",&b[i]);
    }
    for(int i=1;i<=n;i++){
        if(a[i])
             c[++num]=i;
    }
    Dijistra();
/*    cout<<num<<endl;
    for(int i=1;i<=num;i++){
        for(int j=1;j<=num;j++){
            printf("%d %d %d
",i,j,dis[i][c[j]]);
        }
    }*/
    memset(f,0x3f,sizeof(f));
    f[0]=0;
    for(int i=1;i<=num;i++) to[1<<(i-1)]=i;
    for(int i=0;i<=(1<<num)-1;i++){
        for(int j=i;j;j-=j&(-j)){
            int w=to[j&(-j)],sta=j-(j&(-j));
            for(int l=sta;l;l-=l&(-l)){
                int ww=to[l&(-l)];
                f[i]=min(f[i],f[i^(j&(-j))^(l&(-l))]+dis[w][c[ww]]);
            }
        }
    }
    printf("%d
",f[(1<<num)-1]);
}
View Code

    

原文地址:https://www.cnblogs.com/heoitys/p/11336760.html