• 【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
  • 相关阅读:
    XMLHttpRequest简介
    BC30138: 无法在路径“C:\WINDOWS\TEMP\”中创建临时文件: 拒绝访问。
    开机explorer无法启动,无法进入桌面
    选择DataGrid中的CheckBox控件后该行背景变色
    CSS菜单制作工具
    ScriptX打印控件的使用
    JS实时预览上传图片缩略图
    readyState的五种状态详解
    xmlHttpRequest的status的值的含义
    C#调用word打印
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/8955376.html
Copyright © 2020-2023  润新知