设为首页 加入收藏

TOP

Codeforces Round #288 (Div. 2)
2015-07-20 17:22:59 来源: 作者: 【 】 浏览:2
Tags:Codeforces Round #288 Div.

A,B,C水

D。

有一个串,长度为n+2,

现在知道他的所有n个 长度为3的子串是什么

求出原始的串


这题跟POJ 2337有点像

最后抽象出的问题就是求欧拉通路:

将每个长度为3的子串, 前两个字母(数字)看成一个结点, 后两个字母(数字)看成一个结点,

然后这个子串就相当于 一条从前一个结点到后一个结点的边

欧拉通路的要求就是所有边都要走一遍, 所以最后就是求欧拉通路了

结点的个数最大为62*62,边的数量显然就是n了

因为两个字母(数字)hash成数字的话也就是62*62种


首先要判断这个欧拉通路是否存在

首先计算每个结点的入度和出度,

然后如果一个有向图存在欧拉通路。

则任意结点的出度跟入度的差的绝对值 不大于1

并且统计abs(出度-入度)==1 的结点的数量,假设为x个

则x必然为0或者2

如果为0个,则欧拉通路在任意一点都可当做起点

如果为2个,则欧拉通路从(出度-入度)==1 的结点出发


求欧拉通路的时候我们dfs即可,每条边会有一个编号,保证每条边只走一次。

但是需要注意的是,这个n是有20万的, 重边和自环多了会出一些问题。

所以我就将重边看成1条,但是对其计数,在dfs的时候用边的数量当做是否访问过的标记


#include 
  
   
#include 
   
     #include 
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          #include 
          #include 
          
            #define MAXN 111111 #define MAXM 1122222 #define INF 1000000007 #define eps 1e-8 using namespace std; int n; typedef pair
           
             PII; vector
            
              g[66 * 66]; int num[66 * 66]; int in[66 * 66], out[66 * 66]; int fa[66 * 66], v[66 * 66]; int en[66 * 66][66 * 66]; int vis[222222], nv[222222]; int st[222222]; char s[211111][6]; int find(int x) { if(x == fa[x]) return x; int t = find(fa[x]); fa[x] = t; return t; } void join(int x, int y) { int fx = find(x); int fy = find(y); if(fx != fy) fa[fx] = fy; } int getc(char c) { if(c >= 'a' && c <= 'z') return c - 'a'; if(c >= 'A' && c <= 'Z') return c - 'A' + 26; return c - '0' + 52; } int ind; void dfs(int u, int eid) { for(int i = 0; i < g[u].size(); i++) { int tid = g[u][i].second; if(vis[tid]) { vis[tid] --; dfs(g[u][i].first, tid); } } if(eid) st[ind++] = eid; } int main() { scanf("%d", &n); for(int i = 0; i < 66 * 66; i++) fa[i] = i; for(int i = 1; i <= n; i++) { scanf("%s", s[i]); int a = getc(s[i][0]); int b = getc(s[i][1]); int c = getc(s[i][2]); int id1 = a * 62 + b; int id2 = b * 62 + c; v[id1] = 1; v[id2] = 1; join(id1, id2); if(en[id1][id2] == 0) en[id1][id2] = i, g[id1].push_back(PII(id2, i)); in[id2]++; out[id1]++; vis[en[id1][id2]]++; } int tmp = -1, flag = 0; for(int i = 0; i < 66 * 66; i++) { if(!v[i]) continue; if(tmp == -1) tmp = find(i); else { if(tmp != find(i)) { flag = 1; break; } } } int cnt = 0, src = -1; for(int i = 0; i < 66 * 66; i++) { if(!v[i]) continue; if(abs(in[i] - out[i]) >= 2) { flag = 1; break; } else if(abs(in[i] - out[i]) == 1) { cnt ++; if(out[i] - in[i] == 1) src = i; } } if(src == -1) src = tmp; if(flag) { printf("NO\n"); } else if(cnt == 0 || cnt == 2) { dfs(src, 0); printf("YES\n"); for(int i = ind - 1; i >= 0; i--) { int tid = st[i]; if(i == ind - 1) printf("%s", s[tid]); else printf("%c", s[tid][2]); } printf("\n"); } else { printf("NO\n"); } return 0; }
            
           
          
        
       
      
     
    
   
  




E

题意是

给出n个区间。

然后第i个区间表示的是第i个左括号与右括号的 下标距离范围

求出一个合法的括号序列 并且满足这些范围

然后后来想了想,貌似是个记忆化dp, 而且并不难。。

令dp[i][j]表示第i个到第j个左括号是否都成功的匹配到了右括号

那么在dfs的时候,对于dp[i][j] , 我们枚举i被第几个右括号匹配了,显然是从第i个右括号枚举到第j个右括号,假设被第k个右括号匹配并且满足之前给的范围了

然后就可以去寻找其子状态 dp[i + 1][k] 以及dp[k+1][j]


#include 
  
   
#include 
   
     #include 
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          #include 
          #include 
          
            #define MAXN 111111 #define MAXM 1122222 #define INF 1000000007 #define eps 1e-8 using namespace std; int dp[666][666]; int l[666], r[666]; char s[3333]; int n; int p[3333]; int dfs(int L, int R) { if(L > R) return 1; if(dp[L][R]) return dp[L][R]; for(int i = L; i <= R; i++) { if(i - L + 1 >= l[L] && i - L + 1 <= r[L] ) { if(dfs(L + 1, i) == 1 && dfs(i + 1, R) == 1) { p[L] = (i - L) * 2 + 1; return dp[L][R] = 1; } } } return dp[L][R] = -1; } int main() { scanf("%d", &n); int flag = 1; for(int i = 1; i <= n; i++) { scanf("%d%d", &l[i], &r[i]); if(l[i] % 2 == 0) l[i]++; if(r[i] % 2 == 0) r[i]--; if(l[i] > r[i]) { flag = 0; } l[i] = (l[i] + 1) / 2; r[i] = (r[i] + 1) / 2; } if(flag == 0) { printf("IMPOSSIBLE\n"); return 0; } dfs(1, n); if(dp[1][n] != 1) { printf("IMPOSSIBLE\n"); return 0; } int j = 0; for (int i = 1 ; i <= n; i++){ while(s[j]) ++j; s[j] = '('; s[j + p[i]] = ')'; } puts(s); return 0; }
          
        
       
      
     
    
   
  



】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Dictionary and Array value cann.. 下一篇poj1113--Wall(凸包)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·MySQL 基础入门视频 (2025-12-26 23:20:22)
·小白入门:MySQL超详 (2025-12-26 23:20:19)
·关于 MySQL 数据库学 (2025-12-26 23:20:16)
·SOLVED: Ubuntu 24.0 (2025-12-26 22:51:53)
·Linux 常用命令最全 (2025-12-26 22:51:50)