不怕噩梦 (dream.cpp) 蚊子最近经常做噩梦,然后就会被吓醒。这可不好。。疯子一直在发愁,然后突然有一天,他发现蚊子其实就是害怕某些事。如果那些事出现在她的梦里,就会害怕。我们可以假定那个害怕的事其实是一个字符串。而她做的梦其实也是一个字符串。 她可以一个晚上一直做梦,所以梦这个字符串会很长,如果其中包含了她所害怕的事情,那么她这天晚上就会害怕。当然一个害怕的事也可能在这天晚上被她梦到很多遍,当然每个晚上也可能有很多种害怕的事都被梦到。 每个害怕的事都有一定的权值。而这天晚上如果梦到了某件事,那么这件事所产生的黑暗效果等于这件事的权值乘以这个害怕的事在梦字符串里的开始位置。如果同样的事梦到了很多遍,那么就重复上面的操作很多遍。当天晚上的黑暗效果总和等于当天所有害怕的事产生的黑暗效果累加到一起。现在疯子想知道蚊子这些天来噩梦的黑暗效果总和是多少。 INPUT (dream.in): 第1行两个整数N,M代表一共有N天梦和M个害怕的事。 第2行到第M+1行。每行一个字符串ti,代表第I个害怕的事 第M+2行到第2M+2行。每行一个整数ai.代表第I个害怕的事权值 第2M+3行到第N+2M+3行。每行一个字符串si,代表第I天的梦。 OUTPUT(dream.out) SUM SUM=N天里黑暗效果的总和。 我们保证每天的黑暗效果都小于maxlongint; 输入样例 2 2 abc def 1 2 abcdef defabc 输出样例 15 友情提示: 1*1+2*4+1*4+2*1=15 对于数据的把握和时间复杂度的估计是成败的关键。 如果出现一个梦是:ab 而害怕的事有a,b,ab,那么a,b,ab都需要参与计算.. 对于30%的数据 N,M<=50 对于所有的数据 N<=200.M<=200. length(si)<=200.length(ti)<=200.ai<=10.
不怕噩梦:
我提供三种思路:
1. 朴素的模拟。时间大概为O(N*M*length(si)*(length(si)-length(ti))利用均值不等式可以求得时间最大可能达到200^2*100^2。这样期望得分为30分
2. KMP。我想这个算法的理解难度并不大。细心的揣摩一下。可以在O(N*M*length(si))的时间写解决问题。
3. 多字符串匹配机,超过NOIP大纲。
这三种思路仅供参考。
代码我就不放了(绝不是因为我没写)
但是大家一定要牢记:
STL里总会有一些出其不意却又贼jb好用的东西
Code:
#include<cstdio> #include<iostream> #include<cstring> using namespace std; struct node { int val; string s; } f[201]; int n,m; string x; long long ans=0; inline int read() { int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')w=-1; ch=getchar(); } while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48),ch=getchar(); return s*w; } int main() { freopen("dream.in","r",stdin); freopen("dream.out","w",stdout); n=read(),m=read(); for(int i=1; i<=m; i++) std::cin>>f[i].s; for(int i=1; i<=m; i++) f[i].val=read(); for(int i=1; i<=n; i++) { std::cin>>x; for(int j=1; j<=m; j++) { int t=0; while(1) { t=x.find(f[j].s,t); if(t==-1)break; else ans+=(t+1)*f[j].val; t++; } } } cout<<ans; fclose(stdin); fclose(stdout); return 0; }
感谢yu_xuan大佬提供的技术指导