zoukankan      html  css  js  c++  java
  • 2019.10.22 NOIP模拟测试 day2

    T1 入阵曲

    N的范围很小,可以用n^3的方法解决。但是我一开始想的是线段树维护矩阵的和,但是复杂度一直降不下来,还多一个log,最后还没有n^4的暴力高。

    N^4暴力(70分):就是二维前缀和,n^4枚举即可。

    100分做法:

    现预处理出二维前缀和,然后枚举行和列,枚举列可以直接变成少掉一维枚举,就是看是否能被整除,然后开一个桶统计一下就可以了,复杂度n^3。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=505;
    const int nn=1e6+7;
    int a[maxn][maxn];
    long long sum[maxn][maxn];
    int n,m,k;
    long long ans;
    int cnt[nn];
    int b[nn];
    int main(){
        freopen("rally.in","r",stdin);
        freopen("rally.out","w",stdout);
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++) scanf("%d",&a[i][j]);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++) sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
        }
        for(int i=0;i<n;i++){
            for(int j=i+1;j<=n;j++){
                cnt[0]=1;
                for(int o=1;o<=m;o++){
                    b[o]=(sum[j][o]-sum[i][o]+k)%k;
                    ans+=cnt[b[o]];
                    cnt[b[o]]++;
                }
                for(int o=1;o<=m;o++) cnt[b[o]]=0;
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    T2 将军令

    一看,这不是最小点覆盖吗,直接上树形dp最小点覆盖,结果最后wa的很惨。

    正解:树形dp(那是肯定的),只不过dp方程极其复杂,考虑有没有简单一点的方法,当然就是贪心。贪心的枚举每个点最多能覆盖掉的点的个数打标记,用一个堆来存,从深度深的点向它的第k祖先上打标记。看哪些点没被覆盖即可。如果没被覆盖,就增加一个驿站。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+7;
    struct node{
        int nxt,to;
    }edge[maxn*2];
    int head[maxn],cnt;
    int deg[maxn];
    bool vis[maxn];
    void add(int x,int y){
        edge[++cnt].nxt=head[x];
        edge[cnt].to=y;
        head[x]=cnt;
    }
    priority_queue<pair<int,int> >q;
    int fa[maxn];
    int dep[maxn];
    int tot;
    int n,m,k,x,y,t;
    void dfs1(int x){
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].to;
            if(!dep[v]){
                dep[v]=dep[x]+1;
                fa[v]=x;
                dfs1(v);
            }
        }
    }
    void mark(int x,int f,int dep){
        vis[x]=true;
        if(dep==k) return;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==f) continue;
            mark(v,x,dep+1);
        }
    }
    int getfa(int x){
        int num=1;
        while(num<=k){
            x=fa[x];
            num++;
        }
        return x;
    }
    int main(){
        freopen("general.in","r",stdin);
        freopen("general.out","w",stdout);
        scanf("%d%d%d",&n,&k,&t);
        for(int i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        fa[1]=1;dep[1]=1;dfs1(1);
        for(int i=1;i<=n;i++) q.push(make_pair(dep[i],i));
        while(!q.empty()){
            int x=q.top().second;
            q.pop();
            if(vis[x]) continue;
            tot++;
            int kk=getfa(x);
            mark(kk,kk,0);
        }
        printf("%lld
    ",tot);
        return 0;
    }
    View Code

    T3 星空

    输出0,1,2,3运气最好的是输出2,有12分。

    看k的范围很小,就想是否可以状压处理,对于每次区间异或,可以将其转化为差分的形式,维护一个差分数组,然后看差分数组中每个不为0的点的位置所能到达的其他区间,预处理出他们之间的距离,bfs即可。然后就是状压dp。设dp[i]表示状态为i时的最小步数,我们的最终状态是灯全亮,就这样dp下去求解即可。转移方程也非常简单。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+7;
    const int N=550;
    int dis[20][maxn];
    int a[maxn],b[maxn];
    int cha[maxn];
    int n,k,m;
    int cnt[maxn],num;
    int x;
    bool vis[maxn];
    long long dp[1<<20|1];
    int state[N][N];
    void bfs(int x,int *dis){
        queue<int> q;
        memset(vis,false,sizeof(vis));
        q.push(x);
        dis[x]=0;
        vis[x]=1;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=1;i<=m;i++){
                int y=u-b[i];
                if(y>0&&!vis[y]){
                    dis[y]=dis[u]+1;
                    q.push(y);
                    vis[y]=true;
                }
                y=u+b[i];
                if(y<=n+1&&!vis[y]){
                    dis[y]=dis[u]+1;
                    q.push(y);
                    vis[y]=true;
                }
            } 
        }
    }
    int main(){
        freopen("starlit.in","r",stdin);
        freopen("starlit.out","w",stdout);
        scanf("%d%d%d",&n,&k,&m);
        memset(a,1,sizeof(a));
        for(int i=1;i<=k;i++){
            scanf("%d",&x);
            a[x]=0;
        }
        for(int i=1;i<=m;i++) scanf("%d",&b[i]);
        for(int i=1;i<=n+1;i++) cha[i]=a[i]^a[i-1];
        memset(dis,88,sizeof(dis));
        for(int i=1;i<=n+1;i++){
            if(cha[i]){
                cnt[++num]=i;
                bfs(i,dis[num]);
            }
        }
        memset(dp,88,sizeof(dp));
        for(int i=1;i<=num;i++){
            for(int j=1;j<=num;j++){
                state[i][j]=(1<<i-1)|(1<<j-1);
            }
        }
        dp[0]=0;
        int maxx=1<<num;
        for(int i=0;i<maxx;i++){
            for(int j=1;j<=num;j++){
                if((i&(1<<j-1))==0){
                    for(int k=j+1;k<=num;k++){
                        if((i&(1<<k-1))==0){
                            dp[i|(state[j][k])]=min(dp[i|state[j][k]],dp[i]+dis[j][cnt[k]]);
                        }
                    }
                }
            }
        }
        printf("%lld
    ",dp[maxx-1]);
        return 0;
    }
    View Code

  • 相关阅读:
    Atitit.Java exe bat  作为windows系统服务程序运行
    Atitit. Object-c语言 的新的特性  attilax总结
    Atitit. Object-c语言 的新的特性  attilax总结
    Atitit。Time base gc 垃圾 资源 收集的原理与设计
    Atitit。Time base gc 垃圾 资源 收集的原理与设计
    Atitit.go语言golang语言的新的特性  attilax总结
    Atitit.go语言golang语言的新的特性  attilax总结
    Atitit.pdf 预览 转换html attilax总结
    Atitit.pdf 预览 转换html attilax总结
    Atitit.office word  excel  ppt pdf 的web在线预览方案与html转换方案 attilax 总结
  • 原文地址:https://www.cnblogs.com/LJB666/p/11722042.html
Copyright © 2011-2022 走看看