BZOJ 1174: [Balkan2007]Toponyms

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 735  Solved: 102
[Submit][Status][Discuss]

Description

给你一个字符集合,你从其中找出一些字符串出来. 希望你找出来的这些字符串的最长公共前缀*字符串的总个数最大化.

Input

第一行给出数字N.N在[2,1000000] 下面N行描述这些字符串,长度不超过20000 。保证输入文件不超过10MB

Output

a single line with an integer representing the maximal level of complexity Lc(T).

Sample Input

7
Jora de Sus
Orhei
Jora de Mijloc
Joreni
Jora de Jos
Japca
Orheiul Vechi

Sample Output

24

HINT

这题有毒啊,,

思路和算法没什么好说的,

就是建一棵字典树,统计好深度和个数,然后乘起来,取最大值

但是!!!

本蒟蒻一开始写的无限RE

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 int n,sz=1,ans;
 6 string ch;
 7 int a[500001][53],f[500001];
 8 void insert()
 9 {
10     int l=ch.length(),now=0;
11     for(int i=0;i<l;i++)
12     {
13         int t;
14         if(ch[i]==‘ ‘)t=52;
15         else if(ch[i]<=‘Z‘)t=ch[i]-‘A‘;
16         else t=ch[i]-‘a‘+26;
17         if(a[now][t])now=a[now][t];
18         else now=a[now][t]=++sz;
19         f[now]++;
20         ans=max(ans,f[now]*(i+1));
21     }
22 }
23 int main()
24 {
25     scanf("%d",&n);
26     for(int i=1;i<=n;i++)
27     {
28        getline(cin,ch);
29        insert();
30     }
31     printf("%d",ans);
32     return 0;
33 }

RE

后来听别人说这题卡内存,

于是我换成了前向星储存,

然后,

无限TLE,

加了各种常数优化还是无限TLE

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<queue>
 8 using namespace std;
 9 const int MAXN=1001;
10 inline void read(int &n)
11 {
12     char c=‘+‘;bool flag=0;n=0;
13     while(c<‘0‘||c>‘9‘){c=getchar();if(c==‘-‘)flag=1;}
14     while(c>=‘0‘&&c<=‘9‘)n=n*10+c-48,c=getchar();
15 }
16 struct E
17 {
18     int u,v,nxt;
19 }edge[MAXN];
20 int head[MAXN];
21 int num=1;
22 struct node
23 {
24     int bh;
25     int num;
26     int val;
27     node(){num=0;val=0;}
28 }trie[MAXN];
29 int tot=0;
30 char a[MAXN];
31 bool vis[MAXN];
32 inline void add_edge(int x,int y)
33 {
34     edge[num].u=x;
35     edge[num].v=y;
36     edge[num].nxt=head[x];
37     head[x]=num++;
38 }
39 long long int ans=0;
40 inline void insert(char *a)
41 {
42     int l=strlen(a);int now=0;
43     for(register int i=0;i<l;i++)
44     {
45         bool flag=0;
46         int debug=a[i];
47         for(register int j=head[now];j!=-1;j=edge[j].nxt)
48         {
49             if(trie[edge[j].v].val==a[i])
50                 trie[edge[j].v].num++,
51                 flag=1,
52                 now=edge[j].v;
53         }
54         if(flag==0)
55             {
56                 trie[++tot].bh=tot;
57                 trie[tot].num=1;
58                 trie[tot].val=a[i];
59                 add_edge(now,tot);
60                 now=tot;
61             }
62         ans=max(ans,(long long )(i+1)*trie[now].num);
63     }
64 }
65 int main()
66 {
67     memset(head,-1,sizeof(head));
68     int n;
69     read(n);
70     for(int i=1;i<=n;i++)
71     {
72         memset(a,0,sizeof(a));int hh=0;
73         char ch=getchar();bool flag2=0;
74         while(ch==‘\n‘)    ch=getchar();
75         while(ch!=‘\n‘)
76             a[hh++]=ch,ch=getchar();
77         insert(a);
78     }
79     printf("%lld",ans);
80     return 0;
81 }

TLE

然后只好参考别的大神的代码.......

编译速度就秒杀我的代码。。。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define N 5000010
 5 using namespace std;
 6 int tot = 1 , head[N] , to[N] , next[N] , cnt , si[N];
 7 char val[N];
 8 void add(int x , int y , char c)
 9 {
10     to[++cnt] = y , val[cnt] = c , next[cnt] = head[x] , head[x] = cnt;
11 }
12 int main()
13 {
14     int n , i , j , k , t , p;
15     char ch;
16     long long ans = 0;
17     scanf("%d" , &n);
18     for(i = 1 ; i <= n ; i ++ )
19     {
20         ch = getchar();
21         while(ch == ‘\n‘) ch = getchar();
22         for(j = t = 1 ; ch != ‘\n‘ ; j ++ , ch = getchar())
23         {
24             for(p = 0 , k = head[t] ; k ; k = next[k])
25             {
26                 if(val[k] == ch)
27                 {
28                     p = to[k];
29                     break;
30                 }
31             }
32             if(!p) add(t , p = ++tot , ch);
33             t = p , si[t] ++ , ans = max(ans , (long long)j * si[t]);
34         }
35     }
36     printf("%lld\n" , ans);
37     return 0;
38 }
时间: 2024-12-08 05:19:21

BZOJ 1174: [Balkan2007]Toponyms的相关文章

BZOJ1174: [Balkan2007]Toponyms

1174: [Balkan2007]Toponyms Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 117  Solved: 16[Submit][Status] Description 给你一个字符集合,你从其中找出一些字符串出来. 希望你找出来的这些字符串的最长公共前缀*字符串的总个数最大化. Input 第一行给出数字N.N在[2,1000000] 下面N行描述这些字符串,长度不超过20000 总输入不超过20000字符 Output a

bzoj 1176 [Balkan2007]Mokia - CDQ分治 - 树状数组

Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Input 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小 接下来每行为一下三种输入之一(不包含引号): "1 x y a" "2 x1 y1 x2 y2" "3" 输入1:你需要把(x,y)(第x行第y列)的格子权值增加a 输入

BZOJ 1176: [Balkan2007]Mokia

一道CDQ分治的模板题,然而我De了一上午Bug...... 按时间分成左右两半,按x坐标排序然后把y坐标丢到树状数组里,扫一遍遇到左边的就add,遇到右边的query 几个弱智出了bug的点, 一是先分了左右两半再排序,保证的是这次的左右是上次没有计算过的贡献, for(int i=l;i<=r;i++) qs[i].k=(i>mid); sort(qs+l,qs+r+1,cmp2); 然后时间的先后是因为一开始就是按时间排好序的已经保证了. 二是矩阵的一个经典的套路就是拆成四部分差分查询.

【bzoj1174】[Balkan2007]Toponyms Trie树

题目描述 给你一个字符集合,你从其中找出一些字符串出来. 希望你找出来的这些字符串的最长公共前缀*字符串的总个数最大化. 输入 第一行给出数字N.N在[2,1000000] 下面N行描述这些字符串,长度不超过20000 .保证输入文件不超过10MB 输出 a single line with an integer representing the maximal level of complexity Lc(T). 样例输入 7 Jora de Sus Orhei Jora de Mijloc

BZOJ 1176 [Balkan2007]Mokia CDQ分治

题目大意: 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. POJ1195的加强版 没记错的话上午这题还没有中文题目描述的说0.0 好迅速 首先这题看到W就知道二维树状数组挂了 看到M就发现离散化了也搞不了 0.0 这题似乎是CDQ分治被发现之后第二个解决的题目...不过只有会员才知道的世界,今天反应过来刷刷... 修改和询问放在一起分治,一个询问拆分成4个,树状数组处

BZOJ 1170 [Balkan2007]Cipher Hash

题目大意:给定一个二维矩阵,求出现次数最多的a*b的子矩阵 二维Hash,只要记住横纵的BASE不能相同就可以,爱怎么搞怎么搞 一开始写的自然溢出 结果OLE 以为是自然溢出被卡掉了于是写了双取模-- 结果还是OLE 最后发现尼玛这题读入坑爹--字符串里有空格不说,满满的不可见字符是咋回事-- 记住不要用scanf读入--可以用gets,或者fread,注意要把一开始的回车过滤掉 getchar读进来全是错的 不知道怎么回事-- #include <cstdio> #include <c

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

【BZOJ 1176】 [Balkan2007]Mokia

1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MB Submit: 736  Solved: 306 [Submit][Status] Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Input 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小 接下来每行为一下

【BZOJ】1176: [Balkan2007]Mokia(cdq分治)

http://www.lydsy.com/JudgeOnline/problem.php?id=1176 在写这题的时候思维非常逗啊........2333................... 最后不得不去看别人的代码.. 噗,,我怎么没想到二维前缀和.................... orz zyf 那么对于一个矩形,我们拆成四个点,那么就可以和add操作一起cdq分治! orz cdq分治的话很好想的: 定义$solve(l, r)$表示用l~mid来更新mid+1~r. 考虑如何$