汕头市队赛 SRM19 字符题
从天上掉下来了个这样的问题:
有一个字符串 从中选出两个子串 A,B,求 A+B可以构成的不同串的个数。 还想知道,这么多个串中字典序最大的那一个。
某人捡到了这个问题,并把它扔给了你。
【输入】
一个全由小写字母构成的字符串。
【输出】
第一行 一个非负整数,表示两个子串A+B可以构成的不同串个数。由于答案可能很大,所以答案对1004535809取模。
第二行 一个字符串,表示构成的串中字典序最大的。
【样例输入1】
ab
【样例输出1】
11
bb
【样例输入2】
abcaabccba
【样例输出2】
1428
ccccba
【数据范围及约定】
n=|S|
10% n<=10
30% n<=40
另有20% 字符串由1个a和n-1个b构成
100% n<=2000
【提示】
两个子串均可为空,但不同时为空。
这道题我们可以建一棵trie树记录所有子串 计算呢为了防止算重复
我们可以枚举一个子串末尾加上某个字母后是否还是子串
然后就搞来搞去就可以了 至于最大的话就跑一下字典序最大的子串
前面再扔整个序列里面最大的那个字母 能扔几个是几个
#include<cstdio> #include<cstring> #include<algorithm> const int M=5e3+7,mod=1004535809; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } char ch[M],ansq[M]; int ans,s[M],cnt,n,cntq; int c[2000007][27]; void insert(int k){ int rt=0; for(int i=k;i<=n;i++){ if(!c[rt][s[i]]) c[rt][s[i]]=++cnt; rt=c[rt][s[i]]; } } int A[26],B[26]; int dfs(int p){ int sz=1; for(int i=0;i<26;i++){ if(!c[p][i]) A[i]+=(p!=0); else if(!p) B[i]=dfs(c[p][i]); else sz+=dfs(c[p][i]); } return sz; } int main(){ scanf("%s",ch+1); n=strlen(ch+1); for(int i=1;i<=n;i++) s[i]=ch[i]-'a'; for(int i=1;i<=n;i++) insert(i); dfs(0); for(int i=0;i<26;i++) ans=(ans+1LL*(A[i]+1)*B[i]%mod)%mod; printf("%d\n",ans); int rt=0; while(1){ for(int i=25;i>=0;i--)if(c[rt][i]){ ansq[++cntq]=i+'a'; rt=c[rt][i]; goto o; } break; o:; } for(int i=1;i<=cntq;i++) if(ansq[i]==ansq[1]) putchar(ansq[i]); else break; printf("%s",(ansq+1)); return 0; }