zoukankan      html  css  js  c++  java
  • CoFun 1613 单词连接

    Description

    Stan有N个不同的单词,这天,Stan新结交的两个朋友来他这里玩,Stan作为主人,他需要送给他们单词,但由于Stan不能偏心,所以Stan给每个单词一个权值v_i,他需要他这N个单词恰好分配给这两个朋友,这个地方的人很奇怪,他们用来定义自己的喜悦值的方式是把所有得到的单词的权值都位运算and起来的值,所以你需要使得两个朋友的喜悦值是相同的

    好学的Stan不满足于求出一种方案,而是想要知道总共有多少种方案数,Stan觉得这个太简单了,所以请你来帮他解决吧。

    Input Format

    第一行包含一个整数N

    第二行包含N个非负整数,表示每个单词的权值

    Output Format

    输出仅一行,即方案数

    思路:对于每两个字符串,我们考虑A是较小的那个,B是较大的那个,如果AB是回文串,那么BA也一定是回文串。

    所以,假如A是B的前缀,那么B中从len(A)+1到len(B)的部分,若为回文串,那么AB和BA就是子串,因此,我们用manacher预处理是否回文,用字典树维护字典,注意要用链表写字典树才不会爆空间。

     1 #include<algorithm>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<iostream>
     6 #define ll long long
     7 char S[4000005],ss[4000005];
     8 int p[4000005],g[4000005],s[4000005];
     9 int tot,go[4000005],first[4000005],next[4000005],val[4000005],cnt[4000005];
    10 int num[4000005],len[2000005],n;
    11 void manacher(int Len){
    12     int l=0;
    13     S[l]='#';
    14     for (int i=1;i<=Len;i++)
    15      S[++l]=ss[i],S[++l]='#';
    16     int id=0,mx=0;p[0]=0;
    17     for (int i=1;i<=l;i++){
    18         if (mx>=i)
    19          p[i]=std::min(mx-i+1,p[id*2-i]);
    20         else 
    21          p[i]=1;
    22         while (p[i]+i<=l&&i-p[i]>0&&S[p[i]+i]==S[i-p[i]]) p[i]++;
    23         if (i+p[i]-1>mx) mx=i+p[i]-1,id=i; 
    24     }
    25     //g[0]=1;
    26     for (int i=1;i<Len;i++)
    27      if (p[i]>=i)
    28       g[Len-i]=1;
    29      else
    30       g[Len-i]=0;
    31     g[Len]=0;   
    32 }
    33 void insert(int id){
    34     int now=0;
    35     manacher(len[id]);
    36     for (int i=1;i<=len[id];i++){
    37         int k;
    38         for (k=first[now];k!=0;k=next[k])
    39          if (val[k]==s[i]) break;
    40         if (!k){
    41             tot++;
    42             val[tot]=s[i];
    43             next[tot]=first[now];
    44             first[now]=tot;
    45             cnt[tot]=g[i];
    46             now=tot;
    47         }else{
    48           cnt[k]+=g[i];
    49           now=k;    
    50         }
    51     }
    52     num[now]++;
    53 }
    54 int main(){
    55     scanf("%d",&n);
    56     for (int i=1;i<=n;i++){
    57         scanf("%d",&len[i]);
    58         scanf("%s",ss+1);
    59         for (int j=1;j<=len[i];j++)
    60          s[j]=ss[j];
    61         insert(i);
    62     }
    63     ll ans=0;
    64     for (int i=1;i<=tot;i++)
    65      ans+=(ll)num[i]*num[i]+(ll)cnt[i]*num[i]*2;
    66     printf("%lld
    ",ans); 
    67 }
  • 相关阅读:
    .net core 获取程序中文件路径
    关于autofac的一些具体的用法
    Ztree节点增加删除修改和Icheck的用法
    C# 多线程之Task(任务
    C#开启异步 线程的四种方式
    c# thread数线程的创建
    图片转二进制 ,
    循环中如果有某一次循环抛出异常了整个循环就停止的解决办法
    JAVA 8 Optional的使用
    react 获取指定表单对象中的对象的值
  • 原文地址:https://www.cnblogs.com/qzqzgfy/p/5549951.html
Copyright © 2011-2022 走看看