(fzu)Problem I Magic(模拟+后缀匹配)
来源:互联网 发布:森系服装品牌 知乎 编辑:程序博客网 时间:2024/06/04 18:55
Problem Description
Kim is a magician, he can use n kinds of magic, number from 1 to n. We use string Si to describe magic i. Magic Si will make Wi points of damage. Note that Wi may change over time.
Kim obey the following rules to use magic:
Each turn, he picks out one magic, suppose that is magic Sk, then Kim will use all the magic i satisfying the following condition:
1. Wi<=Wk
2. Sk is a suffix of Si.
Now Kim wondering how many magic will he use each turn.
Note that all the strings are considered as a suffix of itself.
Input
First line the number of test case T. (T<=6)
For each case, first line an integer n (1<=n<=1000) stand for the number of magic.
Next n lines, each line a string Si (Length of Si<=1000) and an integer Wi (1<=Wi<=1000), stand for magic i and it’s damage Wi.
Next line an integer Q (1<=Q<=80000), stand for there are Q operations. There are two kinds of operation.
“1 x y” means Wx is changed to y.
“2 x” means Kim has picked out magic x, and you should tell him how many magic he will use in this turn.
Note that different Si can be the same.
Output
For each query, output the answer.
Sample Input
1
5
abracadabra 2
adbra 1
bra 3
abr 3
br 2
5
2 3
2 5
1 2 5
2 3
2 2
Sample Output
3
1
2
1
分析:模拟题
这道题关键在于匹配字符串的后缀,所以可能一不小心时间超限,字符串匹配的算法,匹配后缀,猜想后缀数组可以吧,只是这个比较高级,在挑战程序。。。。中的最后才讲,目前不会。。。
这个题我写得是超限了,问了下AC的大佬,他是模拟卡过去了,看了下好像是我的循环查找的地方有一点没处理好,没记录长度,每次调用strlen()函数,所以会时间超限。。改了一下,AC了(1937ms) 刚好卡过。。
用树做很快,从学长的题解报告知道,可以用字典树。 先给自己普及下做法。。 过段时间再写。。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=1005;int n,q;struct Node{ char a[N]; int cnt;///题中的Wi int len;///字符串a的长度} s[N];int main(){ int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%s%d",s[i].a,&s[i].cnt); s[i].len=strlen(s[i].a); } scanf("%d",&q); int c,x,y; for(int i=0; i<q; i++) { scanf("%d",&c); if(c==1) { scanf("%d%d",&x,&y); s[x].cnt=y; // printf("%d\n",s[x].cnt); } else { scanf("%d",&x); //printf("%d\n",s[x].cnt); int num=1; for(int i=1; i<=n; i++) { if(i==x) continue; int flag; if(s[i].cnt<=s[x].cnt&&s[i].len>=s[x].len) { flag=1; for(int j=s[i].len-1,k=s[x].len-1; k>=0; j--,k--) { //printf("%c %c\n",s[i].a[j],s[x].a[k]); if(s[i].a[j]!=s[x].a[k]) { flag=0; break; } } if(flag) num++; } } printf("%d\n",num); } } } return 0;}
思路:把字符串反转就转化为前缀的问题,这样就可以用字典树来处理是否为前缀问题
然后再用树状数组来维护数量
具体做法是把字符串按长度从小到大插入字典树
对于第i次插入, 若某个结点是结尾结点,则将该点的树状数组更新
因为以该点结尾的字符串是当前插入字符串的前缀
查询操作就是查询第k个字符串结尾的点的树状数组1到w[k]的和
修改操作同样和插入操作类似,把路径上结尾结点的所有树状数组更新
由于只有n个字符串,开n颗树状数组就够了
查询操作O(logN)
修改操作O(len logN)
总复杂度上界O(T * q * len * logN)
*/#include<cstdio>#include<iostream>#include<algorithm>#include<vector>#include<cstring>#include<set>#include<queue>#define LL long long#define P pair<int,int>using namespace std;const int M = 1e5 + 10;const int N = 1e3 + 10;char s[N][N];int n,q;int w[N];int ch[M][26],tot;int has[M * 26],id;int len[N],ran[N],End[N];int sum[N][N];bool cmp(int x,int y){ return len[x] < len[y];}void init(){ id = tot = 0; memset(ch[0],0,sizeof(ch[0])); memset(sum,0,sizeof(sum)); memset(has,0,sizeof(has));}int lowbit(int x){ return x & (-x);}void up(int i,int pos,int val){ while(pos <= 1000){ sum[i][pos] += val; pos += lowbit(pos); }}int getsum(int i,int pos){ int ans = 0; while(pos){ ans += sum[i][pos]; pos -= lowbit(pos); } return ans;}int ix(char c){ return c - 'a';}void Insert(char *s,int v){ int o = 0,c; for(int i = len[v] - 1;i >= 0;i--){ c = ix(s[i]); if(!ch[o][c]){ memset(ch[++tot],0,sizeof(ch[tot])); ch[o][c] = tot; } o = ch[o][c]; if(has[o]) up(has[o],w[v],1); } if(!has[o]){ has[o] = ++id; up(has[o],w[v],1); } End[v] = has[o];}void update(int v,char *s,int y){ int o = 0,c; for(int i = len[v] - 1;i >= 0;i--){ c = ix(s[i]); o = ch[o][c]; if(has[o]){ up(has[o],w[v],-1); up(has[o],y,1); } } w[v] = y;}int main(){ int T; cin>>T; while(T--){ scanf("%d",&n); for(int i = 1;i <= n;i++){ scanf("%s%d",s[i],&w[i]); ran[i] = i; len[i] = strlen(s[i]); } init(); sort(ran+1,ran+n+1,cmp); for(int i = 1;i <= n;i++){ int v = ran[i]; Insert(s[v],v); } scanf("%d",&q); int op,x,y; while(q--){ scanf("%d%d",&op,&x); if(op == 1){ scanf("%d",&y); update(x,s[x],y); }else printf("%d\n",getsum(End[x],w[x])); } } return 0;}
- (fzu)Problem I Magic(模拟+后缀匹配)
- FZU Problem 2280 Magic(Hash)
- (BFS)FZU.Problem 2188 过河I
- G - Train Problem I(模拟题)
- HDU1022 - Train Problem I (模拟)
- FZU 2084(模拟)
- Problem I: 失恋的小T(后缀数组)
- (fzu) Problem D Game(KMP算法,字符串匹配问题)
- 【FZU】Problem 2137 奇异字符串【后缀数组】
- Magic FZU
- Magic FZU
- HDOJ题目1022Train Problem I(栈的模拟)
- hdu 1022 Train Problem I(栈的模拟)
- HDU 1022 Train Problem I (模拟栈)
- hdu 1022 Train Problem I(简单模拟+栈)
- fzu 2104 Floor problem(水题)
- FZU Problem 2110 Star (数学啊 )
- FZU Problem 2112 Tickets (dfs 欧拉图)
- 多重背包
- 活动(Activity)
- 异或密码
- <shader>编程中遇到的问题-too many texture interpolators would be used for ForwardBase pass
- Android多进程模式
- (fzu)Problem I Magic(模拟+后缀匹配)
- Kotlin for Android(七)Kotlin数据类和Gson
- hihocoder1093 SPFA算法模板
- 南师附中集训总结Day4
- Linux下各种错误处理
- 自学PyQuery扎记
- 继承笔记
- 配置Mac的vim,使代码高亮
- Java:模运算