zoukankan      html  css  js  c++  java
  • round 469

    第一次打codeforces,还是太菜了
    代码全部来自大神void_f
    C

    #include <cstdio>
    #include <vector>
    #include <ctype.h>
    using namespace std;
    vector<int> Ans[200010];
    int p,cnt,n=1;
    int main(){
    	for(char ch=getchar();isdigit(ch);ch=getchar(),n++)
    		if(ch=='1'){
    			if(!p){printf("-1
    ");return 0;}
    			Ans[p--].push_back(n);
    		}
                    else if(p==cnt) Ans[p=++cnt].push_back(n);
    		else Ans[++p].push_back(n);
    	
            if(p<cnt){printf("-1
    ");return 0;}
    
    	printf("%d
    ",cnt);
    	for(int i=1;i<=cnt;++i){
    		printf("%d ",Ans[i].size());
    		for(int j=0;j<Ans[i].size();++j)
    			printf("%d ",Ans[i][j]);
    		printf("
    ");
    	}
    	return 0;
    }
    

    求一个1010序列中可以分解为多少个 zebra字串 (以0开始结束 中间01相间的 ,不必要相连 但是先后顺序要一样)
    我们要注意到这样的事实, 就是生成的zerba 并没有顺序,我们可以假想已经生成的zebra,都分别抽取出来,排成一列,而且由于特性的原因,我们可以在维护的过程中,保持前p个 zebra 是以1结尾的(遇见0给p接上,p--) 遇见一(p++ 接上)
    0101
    010
    0
    cnt : 当前生成的zebra 数量
    p : 当前生成的zerba中以1为结尾的数量
    ans _vec
    当时还是没有从这个角度想吧(没能吧字串想的展开)

    D
    数字 1 2 3 4 5 6 7 8
    位置 12345678910 总之是奇数位置上有数字,偶数位置上没有数字
    数学问题,仔细想想,观察移动规律的题,每一次移动都是选取最大的数移动到最近的空
    规律1 所有奇数不会被占有,前1/2 位置的奇数本身就不会挪位,后面的奇数一旦空出位置来就再也不会被取代了
    偶数是有可能被占有的,我们追踪每一个偶数移动的规律
    我们想知道一个偶数位置的数 2*i 上一个位置在哪,那么首先显然这个偶数之前还有空位置,之后已经没有空位置了

    那么这个偶数位置是 2i 那么之前的位置就有i 个数字
    之后的数字就有 n-i-1 个(前面i个数字 ,再包括那个数字本身)
    那么这个数字上一次的位置就应该在
    2
    i + (n-i-1) +1 个处 即 n+i处
    x是偶数,那么上次位置就在 n+x/2 处
    如果一直是偶数就递归处理 直到奇数为止

     #include <cstdio>
    long long n,x;
    int q;
    int main(){
    	scanf("%I64d%I64d",&n,&q);
    	while(q--){
    		scanf("%I64d",&x); 
    		while(!(x&1)) x=(x>>1)+n;
    		printf("%I64d
    ",(x+1)>>1);
    	}
    	return 0;
    }
    

    E 是抽象了就是给定一个有向图,
    对于一个点来说,他的值是从他可以到达点格个数 ,找到值最小的点

    经典算法:
    考虑到有向图,使用tarjan 算法
    时间戳数组 dfn
    标记数组 记录当前节点扩展到的最早节点 low
    同一个low值的节点在一个强联通子图内

    我们将一个可能有环的图通过缩点,变成了一个没有环的图
    找到其中一个没有初度的规模最小的,点就是答案

    方法2:Kosaraju

    首先dfs,但是是后序打标记,就是时间戳.
    然后从上述标机的最大值开始 ,从反向图中进行深搜,每一次如果搜到本轮的节点,就返回 ,搜到前几轮的节点,说明那个轮次的节点不能使用

    理解:
    对于第一次深搜,实际上是给出了,缩点的拓扑排序。
    我们可以保证,将一个强连通子图缩微一点,

    后序的深搜事实上是保证了拓扑排序的正确行。
    确实,理解以后有一种"较大的快感"

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100100;
    int n,m,h,st[N],sz[N],vis[N],cnt,scnt,vd[N],sn[N],a[N];
    vector<int>vec[N],vec2[N];
    
    void dfs1(int x){
    	if(vis[x])return;
    	vis[x]=1;
    	for(int i=0;i<vec[x].size();i++)dfs1(vec[x][i]);
    	st[++cnt]=x;
    }
    void dfs2(int x){
    	if(sn[x]){
    		if(sn[x]!=scnt)vd[sn[x]]=1;
    		return;
    	}
    	sn[x]=scnt;sz[scnt]++;
    	for(int i=0;i<vec2[x].size();i++)dfs2(vec2[x][i]);
    }
    
    
    int main(){
    	scanf("%d%d%d",&n,&m,&h);
    	for(int i=1;i<=n;i++)scanf("%d",a+i);
    	for(int i=1;i<=m;i++){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		if((a[u]-a[v]+h)%h==1)vec[v].push_back(u),vec2[u].push_back(v);
    		if((a[v]-a[u]+h)%h==1)vec[u].push_back(v),vec2[v].push_back(u);
    	}
    	for(int i=1;i<=n;i++)dfs1(i);
    	for(int i=n;i;i--)
    		if(!sn[st[i]]){
    			scnt++;dfs2(st[i]);
    		}
    	int ans=0;sz[0]=n+1;
    	for(int i=1;i<=scnt;i++)if(!vd[i]&&sz[i]<sz[ans])ans=i;
    	printf("%d
    ",sz[ans]);
    	for(int i=1;i<=n;i++)if(sn[i]==ans)printf("%d ",i);
    	return 0;
    }
    
  • 相关阅读:
    【3y】从零单排学Redis【青铜】
    【Java】几道常见的秋招面试题
    【Java】广州三本秋招经历
    两个月的Java实习结束,继续努力
    外行人都能看懂的SpringCloud,错过了血亏!
    【Java】留下没有基础眼泪的面试题
    【Java】几道让你拿offer的知识点
    Java多线程打辅助的三个小伙子
    数据库两大神器【索引和锁】
    Linux网络管理
  • 原文地址:https://www.cnblogs.com/sfzyk/p/8536821.html
Copyright © 2011-2022 走看看