zoukankan      html  css  js  c++  java
  • 牛客网NOIP赛前集训营提高组(第七场)Solution

    先吐槽一下,这次的比赛稍微有点水了。。。\(kcz\) 神仙 \(40min\) 做完 \(3\) 道题 \(rank1\) 到最后竟然掉了 \(73\) 分。。。

    Problem A. 中国式家长 2

    大水题,直接按题意模拟即可,没什么好说的,全场切,\(kcz\) 神仙 \(6min\)
    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int N=2e2+10;
    int n,m,k,T,a[N][N],x,y,Walk,IQ;
    int dx[8]={-1,-1,0,1,1,1,0,-1},dy[8]={0,1,1,1,0,-1,-1,-1};
    bool b[N][N],Dig[N][N];
    int main(){
        scanf("%d%d%d",&n,&m,&k);Walk=k;
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=m;j++)
                scanf("%d",&a[i][j]);
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=m;j++)
                scanf("%d",&b[i][j]);
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&x,&y);
            if(!b[x][y]||Dig[x][y]||(!a[x][y]&&Walk<10)){printf("-1 -1\n");return 0;}
            Dig[x][y]=true;
            for(register int i=0;i<=7;i++)b[x+dx[i]][y+dy[i]]=true;
            if(!a[x][y])Walk-=10,IQ+=10;
            else Walk=min(Walk+a[x][y],k);
        }
        printf("%d %d\n",Walk,IQ);return 0;
    }
    

    Problem B. 随机生成树

    问题可以转化为把 \(n\) 个点按题意连接后,颜色相同且联通的一块被称为一个联通块,求最多有多少联通块
    题目要求它的父亲必须是它的约数,那么我们考虑枚举每一个数的约数,显然这样做复杂度是 \(O(n\sqrt n)\) 级别的,这也是为什么本题时限竟然有 \(2s\),因为常数小一点这样的乱搞也能过。(PS:我最近都被暴力吓怕了,前两次模拟赛有三道题全部给了暴力满分,这回暴力写的好也过了,真不知道出题人是怎么想的)
    我们当然不会满足于这样的乱搞算法,所以很快,我们就想到另一种更优的算法:直接对于每个数枚举它的倍数,然后对应更新答案即可。因为要让联通块尽量的多,那么每个点都要尽量往与它颜色不同的节点上连,这样贪心下去就可以保证是最优的了,复杂度大概是 \(O(n\log n)\),所以这道题数据范围扩大到 \(5000000\) 都没有问题。
    这题 \(kcz\) 只用了 \(4min\) 就切掉了。。。
    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int N=5e5+10;
    int n,a[N],fa[N],head[N],cnt,pre[N],ans;
    struct edge{int nxt,to;}ed[N];
    inline void addedge(int x,int y){ed[++cnt].to=y;ed[cnt].nxt=head[x];head[x]=cnt;}
    inline void DFS(int u){
        pre[u]=ans;
        for(register int i=head[u];i;i=ed[i].nxt)
            if(a[u]==a[ed[i].to])DFS(ed[i].to);
    }
    int main(){
        scanf("%d",&n);
        for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(register int i=1;i<=n;i++){
            if(i!=1)addedge(fa[i],i);
            for(register int j=(i<<1);j<=n;j+=i)
                if(!fa[j])fa[j]=i;else if(a[i]!=a[j])fa[j]=i;
        }
        for(register int i=1;i<=n;i++)if(!pre[i])++ans,DFS(i);
        printf("%d\n",ans);return 0;
    }
    

    Problem C. 洞穴

    这题思想挺不错的,当时在考场上已经想差不多了,就是设 \(dis[i][j][k]\) 表示从 \(i\)\(k\) 步是否可以到达 \(j\),但没想到倍增,硬设肯定是不行的,毕竟最多要走十亿多步,然后就陷入了图中环的深渊无法自拔,瞎转移一波成功得到了 \(5\) 分。。。接下来说说正解
    还是和上面差不多,我们设 \(dis[i][j][k]\) 表示从 \(i\)\(2^j\) 步是否可以到达 \(k\),然后我们发现这东西的值只有 \(0\)\(1\),所以直接用 \(bitset\) 把最后一维压掉,这样位运算的复杂度就变成了 \(O(N/64)\) 了,可以加快速度
    然后考虑转移,如果 \(i\)\(2^j\) 步可以到达 \(k\),那么显然 \(i\)\(2^{j+1}\) 步就可以达到 \(k\)\(2^j\) 步所能达到的所有节点,那么就有以下的转移方式

    \[dis[i][j+1]|=dis[k][j],dis[i][j][k]==1 \]

    这样我们就完成了预处理
    那么我们这样倍增到底有什么好处呢?可以发现,对于每一个询问里的 \(l\),它在二进制下都由若干个 \(1\) 组成,那么我们只要找到这些 \(1\),并将当前可到达的节点倍增走出去即可。例如当前可以走到的节点状态为 \(ans\)\(bitset\) 压位),那么我们就可以枚举 \(ans\) 所有不为 \(0\) 的位置,然后用 \(dis[i][j]\) 再往外走就行了
    复杂度大概为 \(O(\frac{Qlogln^2}{64}+\frac{n^3logn}{64})\),代码如下:
    #include<cstdio>
    #include<iostream>
    #include<bitset>
    using namespace std;
    const int N=1e2+10;
    const int LOG=31;
    int n,m,U,V,l,a,b,Q;
    bitset<N>dis[N][33],ans,tmp;
    int main(){
    	scanf("%d%d",&n,&m);
    	for(register int i=1;i<=m;i++)
    		scanf("%d%d",&U,&V),dis[U][0][V]=1;
    	for(register int j=0;j<=LOG;j++)
    		for(register int i=1;i<=n;i++)
    			for(register int k=1;k<=n;k++)
    				if(dis[i][j][k])dis[i][j+1]|=dis[k][j];//若数组紧贴着LOG开这里加一会超过范围!!! 
    	scanf("%d",&Q);
    	while(Q--){
    		scanf("%d%d%d",&l,&a,&b);
    		ans.reset();ans[a]=1;
    		for(register int i=0;i<=LOG;i++){
    			if(!(l>>i))break;
    			if((l>>i)&1){
    				tmp=ans;ans.reset();
    				for(register int j=1;j<=n;j++)if(tmp[j])ans|=dis[j][i];
    			}
    		}
    		puts(ans[b]? "YES":"NO");
    	}
    	return 0;
    }
    
  • 相关阅读:
    R语言与概率统计(三) 多元统计分析(上)
    R语言与概率统计(二) 假设检验
    win系统下启动linux上的kafka集群及使用
    MD5加密解密帮助类
    Effective JavaScript Item 39 绝不要重用父类型中的属性名
    博客搬家啦!
    ABAP 中的搜索帮助
    &lt;转&gt;bash: qmake: command not found...
    EJB学习笔记六(EJB中的拦截器)
    需求管理之被遗忘的需求
  • 原文地址:https://www.cnblogs.com/ForwardFuture/p/9866333.html
Copyright © 2011-2022 走看看