zoukankan      html  css  js  c++  java
  • 【FZU2280】Magic

    题意

      给出n个字符串,每个字符串有一个权值wi 有q个操作,操作有两种 1 x y 将字符串x的权值变为y 2 x 查询操作,输出以字符串x为后缀,且权值小于等于wx的字符串个数。其中n<=1000 每个字符串长度<=1000 询问q<=80000。

    分析

      n并不大,但是q太大了。如果暴力的话,每次查询都是o(n*len)的,肯定不行。

      等等,谁说不行?我试试 emmm。。。爆过去了????下面是瞎几把爆的代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 const int maxn=1000+10;
     8 int len[maxn],w[maxn];
     9 char s[maxn][maxn];
    10 int T,n,q;
    11 
    12 int main(){
    13     scanf("%d",&T);
    14     for(int t=1;t<=T;t++){
    15         scanf("%d",&n);
    16         for(int i=1;i<=n;i++){
    17             scanf("%s",s[i]);
    18             scanf("%d",&w[i]);
    19             len[i]=strlen(s[i]);
    20         }
    21         scanf("%d",&q);
    22         int opt;
    23         for(int i=1;i<=q;i++){
    24             scanf("%d",&opt);
    25             if(opt==1){
    26                 int x,y;
    27                 scanf("%d%d",&x,&y);
    28                 w[x]=y;
    29             }else if(opt==2){
    30                 int x;
    31                 scanf("%d",&x);
    32                 int ans=0;
    33                 for(int j=1;j<=n;j++){
    34                     if(w[j]>w[x])continue;
    35                     if(len[j]<len[x])continue;
    36                     bool ok=1;
    37                     for(int k=len[j]-1,l=len[x]-1;l>=0;k--,l--){
    38                         if(s[x][l]!=s[j][k]){
    39                             ok=0;
    40                             break;
    41                         }
    42                     }
    43                     if(ok){
    44                         ans++;
    45                        // cout<<j<<endl;
    46                     }
    47                 }
    48                 printf("%d
    ",ans);
    49             }
    50         }
    51     }
    52 return 0;
    53 }
    View Code

    好吧好吧,上面那个不算,我们重新来想···

     后缀嘛,后缀数组?咳,我就知道名字而已不会。。想点会的。。

      字典树行不行?我们只要把字符串倒着插进去就可以用统计前缀的方法来统计后缀了。

      w这个限制怎么办?

      我们在字典树上每一个字符串结尾维护一个vector···这样··时间复杂度是多少?均摊下应该是···可以的···吧?

      

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <iostream>
      5 #include <vector>
      6 using namespace std;
      7 const int maxn=1000+10;
      8 int ch[maxn*maxn][30],W[maxn];
      9 char s[maxn][maxn];
     10 int val[maxn*maxn];
     11 vector<int>G[maxn*maxn];
     12 int T,n,q,sz;
     13 void insert(char *s,int w){
     14     int len=strlen(s);
     15     int u=0;
     16     for(int i=0;i<len;i++){
     17         int id=s[i]-'a';
     18         if(!ch[u][id]){
     19             ch[u][id]=++sz;
     20         }
     21         u=ch[u][id];
     22     }
     23     G[u].push_back(w);
     24     return ;
     25 }
     26 void tra(int u){
     27   /*  if(G[u].size()!=0){
     28         for(int i=0;i<G[u].size();i++){
     29             printf("%d ",G[u][i]);
     30         }
     31         return;
     32     }*/
     33     for(int i=0;i<26;i++){
     34         if(ch[u][i]){
     35           printf("%c",i+'a');
     36           tra(ch[u][i]);
     37         }
     38     }
     39     return;
     40 }
     41 int ans;
     42 void check(int u,int k){
     43     if(G[u].size()){
     44         for(int i=0;i<G[u].size();i++){
     45             if(W[G[u][i]]<=W[k]){
     46                 ans++;
     47             }
     48         }
     49     }
     50     for(int i=0;i<26;i++){
     51         if(ch[u][i])
     52             check(ch[u][i],k);
     53     }
     54     return;
     55 }
     56 void solve(int k){
     57     int u=0;
     58     ans=0;
     59     for(int i=strlen(s[k])-1;i>=0;i--){
     60         int id=s[k][i]-'a';
     61         if(!ch[u][id]){
     62             return ;
     63         }
     64         u=ch[u][id];
     65     }
     66     check(u,k);
     67     return ;
     68 }
     69 int main(){
     70     scanf("%d",&T);
     71     for(int t=1;t<=T;t++){
     72         scanf("%d",&n);
     73         for(int i=0;i<=1000*1000;i++)G[i].clear();
     74         memset(val,0,sizeof(val));
     75         memset(ch,0,sizeof(ch));
     76         sz=0;
     77         char s1[maxn];
     78         int x;
     79         for(int i=1;i<=n;i++){
     80             scanf("%s%d",s[i],&W[i]);
     81             for(int j=0;j<strlen(s[i]);j++){
     82                 s1[j]=s[i][strlen(s[i])-1-j];
     83             }
     84             s1[strlen(s[i])]='';
     85             insert(s1,i);
     86         }
     87        // tra(0);
     88 
     89        scanf("%d",&q);
     90        for(int i=1;i<=q;i++){
     91             int opt;
     92             scanf("%d",&opt);
     93             if(opt==1){
     94                 int x,y;
     95                 scanf("%d%d",&x,&y);
     96                 W[x]=y;
     97             }else if(opt==2){
     98                 int x;
     99                 scanf("%d",&x);
    100                 solve(x);
    101                 printf("%d
    ",ans);
    102             }
    103        }
    104     }
    105 return 0;
    106 }
    View Code
  • 相关阅读:
    位军营 20190919-4 测试,结对要求
    位军营 20190919-5 代码规范,结对要求
    国内源
    hexo安装-nodejs
    python调用chrome打开指定网址
    生成证书,用于签名Android应用
    cygwin64-安装包管理工具
    Android-删除指定包名的App
    pyqt5加载网页的简单使用
    打包python到exe
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/8955376.html
Copyright © 2011-2022 走看看