题意:如果两个单词首尾字母相同,仅中间字母的顺序被打乱,这两个单词被视作相等的。给定一个dictionary (a list of words),一个sentence,问有多少个dictionary中的单词出现在sentence里面。
赛后发现小数据竟然可以暴力水过o(╯□╰)o。对于每一个单词,遍历sentence中相同长度的子串,如果首尾子母相同,就把中间部分sort之后,判断两个单词是否相等。
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<windows.h>
using namespace std;
//Problem C Google Kickstart 2018
const int maxn=1010;
int T;
int N;
int L;
int A;
int B;
int C;
int D;
char arr[maxn];
string dict[maxn];
char S1;
char S2;
long long x[maxn];
int ans;
int main()
{
// string a="ee";
// sort(a.begin()+1,a.end()-1);
// cout<<a<<endl;
// return 0;
// freopen("input.txt","r",stdin);
freopen("C-small-practice.in","r",stdin);
freopen("C.txt","w",stdout);
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
memset(arr,0,sizeof(arr));
memset(x,0,sizeof(x));
ans=0;
//memset(dict,0,sizeof(dict));
scanf("%d",&L);
for(int i=0;i<L;i++)
{
cin>>dict[i];
sort(dict[i].begin()+1,dict[i].end()-1);
}
cin.ignore();
scanf("%c %c %d %d %d %d %d",&S1,&S2,&N,&A,&B,&C,&D);
//cout<<S1<<" "<<S2<<" "<<N<<" "<<A<<" "<<B<<" "<<C<<" "<<D<<endl;
x[0]=S1-'a'+97;
x[1]=S2-'a'+97;
arr[0]=S1;
arr[1]=S2;
for(int i=2;i<N;i++)
{
x[i]=(A%D)*(x[i-1]%D)+(B%D)*(x[i-2]%D)+C%D;//mod 26 to avoid overflow?
x[i]%=D;
arr[i]=97+x[i]%26;
}
// cout<<arr<<endl;
// char cmparr[]="aapxjdnrbtvldptfzbbdbbzxtndrvjblnzjfpvhdhhpxjdnrbt";
// if(strcmp(cmparr,arr)==0)
// {
// cout<<"ok"<<endl;
// }
for(int i=0;i<L;i++)
{
//cout<<dict[i]<<endl;
for(int j=0;j<N;j++)
{
//cout<<j<<endl;
//cout<<dict[i][0]<<" "<<arr[j]<<" "<<dict[i][dict[i].length()-1]<<" "<<arr[j+dict[i].length()-1]<<endl;
if(j+dict[i].length()<=N&&dict[i][0]==arr[j]&&dict[i][dict[i].length()-1]==arr[j+dict[i].length()-1])
{
//cout<<"here"<<endl;
char tmparr[100010];
for(int k=j;k<j+dict[i].length();k++)
{
tmparr[k-j]=arr[k];
}
tmparr[dict[i].length()]='\0';
//cout<<tmparr<<endl;
sort(tmparr+1,tmparr+dict[i].length()-1);
bool flg=true;
for(int k=0;k<dict[i].length();k++)
{
if(dict[i][k]!=tmparr[k])
{
flg=false;
break;
}
}
if(flg==true)
{
ans++;
break;
}
}
}
}
printf("Case #%d: %d\n",ca,ans);
}
return 0;
}
其实大数据也木有完全解决,大概跑9-10min能跑完。
在给定一个Word with length l遍历sentence时候,S[i,i+l]与S[i+1,i+l+1]中间的l-2的letter都是重合的,所以不需要每次都重新compare S[i,i+l]与Word是否相同。因为只有26个字母,可以通过维护一个frequency array实现,e.g, freq_array[0,1,2,3,..26],freq_array[0]表示sub string S[i,i+l]中a出现的次数。Then from S[i,i+l] to S[i+1,i+l+1],只需要改变S[i]和S[i+l+1]对应的freq_array的值即可。
large input无法用O(LN)暴力枚举。但是隐含条件说dictionary中Word length之和M<=1e5。M限制了word length的种类个数。word length 种类假设有X种,那么最多的情况是每个Word的length都只有一个,即1+2+...+X<=M,因此X=447.21,scale小了很多。
因此可以将相同length的Word的frequency array存在一个multiset里面(和set相比multiset允许重复的元素),对于每个出现过的length,遍历subsrting,在multiset中查找对应的frequency array是否有word出现过。因为每个Word只统计是否出现,查找到的Word需要从set中删除。为了保证首位letter相同,frequency array再加两项表示首尾字母即可。
因为multiset不能存数组(需要copy等操作),所以先转换成了array存进去,c++11中的array<type,int>可以直接存在set里面。以后再看看。
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<ctype.h>
#include<map>
#include<time.h>
#include<set>
#include<bitset>
#include<sstream>
using namespace std;
//2018 round A Problem C. Scrambled Words
const int maxn=1000010;
int T;
int N;
int A;
int B;
int C;
int D;
int L;
char S1;
char S2;
long long x[maxn];
char S[maxn];
int ans;
//string dict[20010];
char dict[20010][100010];
int freq_array[20010][28];//record frequency array + the 1st and the last letter
multiset<string>wordset[447];// save frequency array of words with the same length
map<int,int>mp;//map word length to index of multiset
string convert_to_string(int a[],int len)
{
string ret="";
for(int i=0;i<len;i++)
{
ret+=a[i];
// stringstream stream;
// stream<<a[i];
// string string_temp=stream.str();
// ret+=string_temp;
ret+=",";
}
return ret;
}
int main()
{
cin>>T;
for(int ca=1;ca<=T;ca++)
{
// cout<<ca<<endl;
memset(x,0,sizeof(x));
memset(dict,0,sizeof(dict));
memset(freq_array,0,sizeof(freq_array));
memset(S,0,sizeof(S));
for(int i=0;i<150;i++)
{
wordset[i].clear();
}
ans=0;
mp.clear();
// cin>>L;
scanf("%d",&L);
for(int i=0;i<L;i++)
{
// cin>>dict[i];
scanf("%s",dict[i]);
// cout<<dict[i]<<" "<<strlen(dict[i])<<endl;
}
cin.ignore();//otherwise, can not input the following characters.
// cin>>S1>>S2>>N>>A>>B>>C>>D;
scanf("%c %c %d %d %d %d %d",&S1,&S2,&N,&A,&B,&C,&D);
x[0]=S1-'a'+97;
x[1]=S2-'a'+97;
S[0]=S1;
S[1]=S2;
for(int i=2;i<N;i++)
{
x[i]=(A%D)*(x[i-1]%D)+(B%D)*(x[i-2]%D)+C%D;
x[i]%=D;
S[i]=97+(x[i]%26);
}
// cout<<S<<endl;
int cnt=0;
// cout<<L<<endl;
// int tot_len=0;
// set<int>set_len=set<int>();
for(int i=0;i<L;i++)
{
int len=strlen(dict[i]);
for(int j=0;j<len;j++)
{
int letter=dict[i][j]-'a';
freq_array[i][letter]++;
}
freq_array[i][26]=dict[i][0]-'a';
freq_array[i][27]=dict[i][len-1]-'a';
// int len=dict[i].length();
// tot_len+=len;
// set_len.insert(len);
if(mp.find(len)==mp.end())
{
mp[len]=cnt++;
}
// cout<<i<<" "<<cnt<<endl;
string tmp=convert_to_string(freq_array[i],28);
// cout<<tmp<<endl;
wordset[mp[len]].insert(tmp);
}
// cout<<tot_len<<endl;
// cnt=0;
// for(auto it=set_len.begin();it!=set_len.end();it++)
// {
// cnt++;
// cout<<*it<<endl;
// }
// cout<<"total cnt "<<cnt<<endl;
// cout<<"here"<<endl;
// cout<<cnt<<endl;
for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++)
{
int len=it->first;
int idx=it->second;
if(len>N)
{
continue;
}
int tmp_freq_array[28];
memset(tmp_freq_array,0,sizeof(tmp_freq_array));
// cout<<"len "<<len<<endl;
//initilize
for(int i=0;i<len-1;i++)
{
int letter=S[i]-'a';
tmp_freq_array[letter]++;
}
for(int i=0;i+len<=N;i++)//should be <=N instead of <N, since we include S[i]
{
int letter1=S[i]-'a';
int letter2=S[i+len-1]-'a';
tmp_freq_array[26]=letter1;
tmp_freq_array[27]=letter2;
tmp_freq_array[letter2]++;
// cout<<i<<" "<<letter1<<" "<<letter2<<endl;
string tmp=convert_to_string(tmp_freq_array,28);
int tmp_cnt=wordset[idx].count(tmp);
if(tmp_cnt!=0)
{
// cout<<tmp_cnt<<endl;
ans+=tmp_cnt;
wordset[idx].erase(tmp);//count each word at most once
}
tmp_freq_array[letter1]--;//will not be in the next frame
}
}
printf("Case #%d: %d\n",ca,ans);
}
return 0;
}