Problem C. Scrambled Words Google Kickstart Round A 2018

题意:如果两个单词首尾字母相同,仅中间字母的顺序被打乱,这两个单词被视作相等的。给定一个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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值