无聊的活动/缘生意转(2018 Nova OJ新年欢乐赛B题)解题报告

题目2(下面的太抓 我重新写了个背景 其他都一样)

无聊的活动


  JLZ老师不情愿的参加了古风社一年一度的活动,他实在不觉得一群学生跳舞有什么好看,更不明白坐在身后的学生为什么这么兴奋(看小姐姐),于是露出了相当无聊+严肃的表情。
  这不公平!因为他旁边的XBS老师是机器人!真正的XBS,在办公室里睡觉!
  不过,他有一个艰巨的任务!那就是!做游戏!
  这里的歌词有好多都带数字,比如“二十四桥明月不若此时节”、“三五各掌花灯盈盈各眉眼”,X老师把歌词翻译成英文,再由机器人筛选并翻译成阿拉伯数字。
  现在机器人XBS会挑出含义为小于100的自然数的单词,并将答案加上该数。其余单词均表示0。
  如果不这样做,机房的孩子就不能考试了!(╯‵□′)╯︵┻━┻

 

接下来的两种方法常数差不多,都挺小的

std3:在std2的基础上优化,用字符串长度+首字母+尾字母进行哈希

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<map>
 4 #include<string>
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<ctime>
 8 using namespace std;
 9 int n,ans,len,val,list[10010][120];
10 char s[22];
11 char dic[120][22]={"one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four","twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three","thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three","forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three","fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine","sixty","sixty-one","sixty-two","sixty-three","sixty-four","sixty-five","sixty-six","sixty-seven","sixty-eight","sixty-nine","seventy","seventy-one","seventy-two","seventy-three","seventy-four","seventy-five","seventy-six","seventy-seven","seventy-eight","seventy-nine","eighty","eighty-one","eighty-two","eighty-three","eighty-four","eighty-five","eighty-six","eighty-seven","eighty-eight","eighty-nine","ninety","ninety-one","ninety-two","ninety-three","ninety-four","ninety-five","ninety-six","ninety-seven","ninety-eight","ninety-nine"};
12 int check()
13 {
14     len=strlen(s),val=len+((s[0]-'a')<<3)+((s[len-1]-'a')<<7);
15     for(int i=1;i<=list[val][0];++i){
16         for(int j=0;j<len;++j){
17             if(s[j]!=dic[list[val][i]][j]) break;
18             if(j==len-1) return list[val][i]+1;
19         }
20     }
21     return 0;
22 }
23 void init()
24 {
25     for(int i=0;i<99;++i){
26         len=strlen(dic[i]);
27         val=len+((dic[i][0]-'a')<<3)+((dic[i][len-1]-'a')<<7);
28         list[val][++list[val][0]]=i;
29     }
30 }
31 int main()
32 {
33     freopen("numstring10.in","r",stdin);
34     freopen("numstring10.out","w",stdout);
35     //int st=clock();
36     init();
37     cin>>n;
38     for(int i=1;i<=n;++i){
39         scanf("%s",s);
40         ans+=check();
41     }
42     cout<<ans<<endl;
43     //cout<<clock()-st;
44     return 0;
45 }

std4 打完表直接trie

#include<bits/stdc++.h> //https://www.luogu.org/problem/P2580
#define maxn 500010
using namespace std;
int trie[maxn][30],val[maxn],cnt,n;
char str[110];
char dic[120][22]={"one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four","twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three","thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three","forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three","fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine","sixty","sixty-one","sixty-two","sixty-three","sixty-four","sixty-five","sixty-six","sixty-seven","sixty-eight","sixty-nine","seventy","seventy-one","seventy-two","seventy-three","seventy-four","seventy-five","seventy-six","seventy-seven","seventy-eight","seventy-nine","eighty","eighty-one","eighty-two","eighty-three","eighty-four","eighty-five","eighty-six","eighty-seven","eighty-eight","eighty-nine","ninety","ninety-one","ninety-two","ninety-three","ninety-four","ninety-five","ninety-six","ninety-seven","ninety-eight","ninety-nine"};
void insert(char *s,int w){
    int len=strlen(s),p=0;
    for(int i=0;i<len;++i){
        int id=s[i]-'a';
        if(!trie[p][id]) p=trie[p][id]=++cnt; 
        else p=trie[p][id];
    }
    val[p]=w;
}
int query(char *s){
    int len=strlen(s),p=0;
    for(int i=0;i<len;++i){
        int id=s[i]-'a';
        if(!trie[p][id]) return 0;
        else p=trie[p][id];
    }
    return val[p];
}
int main(){
    for(int i=0;i<100;++i){
        insert(dic[i],i+1);
    }
    cin>>n;
    int ans=0;
    for(int i=1;i<=n;++i){
        scanf("%s",str);
        ans+=query(str);
    }
    cout<<ans<<endl;
    return 0;
}

——————————分割线——————————

题目

写在前面

好像是网络问题导致我无法在电脑上看评测记录,不过根据Wahacer dalao发来的截图……

这些画风清奇的打表已经完美诠释了什么叫暴力美学(噗)。

其实也没关系,因为本题的正解就是暴力+优hu化gao,由于要面向新高一同学就出的比较水(然而真相是我想不出来难题)。

正文

最初的想法是,把难点设在构造1-99的单词上,直接塞进map就做完了,了解一下构造方法。

(std1 因为map带一个log 会被卡)

 1 #include<cstdio>
 2 #include<map>
 3 #include<ctime>
 4 #include<string>
 5 #include<iostream>
 6 #include<algorithm>
 7 using namespace std;
 8 map<string,int>mp;
 9 int n,ans;
10 string tmp;
11 char s[22];
12 string I[110]={"","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"};
13 string II[110]={"twen","thir","four","fif"};
14 void trans(){if(tmp[0]=='e') tmp.erase(tmp.size()-1,tmp.size());}
15 void init()
16 {    
17     for(int i=0;i<=12;++i) mp[I[i]]=i;
18     for(int i=13;i<=19;++i){
19         tmp=(i<=15?II[i-12]:I[i-10]);
20         trans();
21         mp[tmp+"teen"]=i;
22     }
23     II[2]="for";
24     for(int i=2;i<=9;++i){
25         tmp=(i<=5?II[i-2]:I[i]);
26         trans();
27         tmp+="ty";
28         mp[tmp]=i*10;
29         for(int j=1;j<=9;++j) mp[tmp+"-"+I[j]]=i*10+j;
30     }
31 }
32 int main()
33 {
34     //freopen("numstring10.in","r",stdin);
35     //int st=clock();
36     init();
37     cin>>n;
38     while(n--){
39         scanf("%s",s);
40         tmp=string(s);
41         ans+=mp[tmp];
42     }
43     cout<<ans<<endl;
44     //cout<<clock()-st;
45     return 0;
46 }

大致思路是把要用的部分打一个小小的表然后就可以构造十几和几十几的单词了,很简单吧。特别注意eighty的t要去掉一个(程序中的trans函数);构造“几十”之前把“four”变成“for”。(果然是考察小学英语)

不过鉴于很多高一的同学还没有学map,下面70分暴力先了解一下——

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<map>
 4 #include<string>
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<ctime>
 8 using namespace std;
 9 int n,ans;
10 char s[22];
11 char dic[120][22]={"one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four","twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three","thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three","forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three","fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine","sixty","sixty-one","sixty-two","sixty-three","sixty-four","sixty-five","sixty-six","sixty-seven","sixty-eight","sixty-nine","seventy","seventy-one","seventy-two","seventy-three","seventy-four","seventy-five","seventy-six","seventy-seven","seventy-eight","seventy-nine","eighty","eighty-one","eighty-two","eighty-three","eighty-four","eighty-five","eighty-six","eighty-seven","eighty-eight","eighty-nine","ninety","ninety-one","ninety-two","ninety-three","ninety-four","ninety-five","ninety-six","ninety-seven","ninety-eight","ninety-nine"};
12 int check()
13 {
14     for(int i=0;i<99;++i){
15         //int len1=strlen(s),len2=strlen(dic[i]);
16         //if(len1!=len2) continue;
17         for(int j=0;j<len1&&j<len2;++j){
18             if(s[j]!=dic[i][j]) break;
19             if(j==len1-1) return i+1;
20         }
21     }
22     return 0;
23 }
24 int main()
25 {
26     //freopen("numstring10.in","r",stdin);
27     //int st=clock();
28     cin>>n;
29     for(int i=1;i<=n;++i){
30         scanf("%s",s);
31         ans+=check();
32     }
33     cout<<ans<<endl;
34     //cout<<clock()-st;
35     return 0;
36 }

如果我们打表了但只写暴力查找就会被3e6的范围卡掉。

真·标程了解一下——

(std2 教师机太慢了 过不去 luogu还可以)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<map>
 4 #include<string>
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<ctime>
 8 using namespace std;
 9 int n,ans,len,list[22][120];
10 char s[22];
11 char dic[120][22]={"one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four","twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three","thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three","forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three","fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine","sixty","sixty-one","sixty-two","sixty-three","sixty-four","sixty-five","sixty-six","sixty-seven","sixty-eight","sixty-nine","seventy","seventy-one","seventy-two","seventy-three","seventy-four","seventy-five","seventy-six","seventy-seven","seventy-eight","seventy-nine","eighty","eighty-one","eighty-two","eighty-three","eighty-four","eighty-five","eighty-six","eighty-seven","eighty-eight","eighty-nine","ninety","ninety-one","ninety-two","ninety-three","ninety-four","ninety-five","ninety-six","ninety-seven","ninety-eight","ninety-nine"};
12 int check()
13 {
14     len=strlen(s);
15     for(int i=1;i<=list[len][0];++i){
16         for(int j=0;j<len;++j){
17             if(s[j]!=dic[list[len][i]][j]) break;
18             if(j==len-1) return list[len][i]+1;
19         }
20     }
21     return 0;
22 }
23 void init()
24 {
25     for(int i=0;i<99;++i){
26         len=strlen(dic[i]);
27         list[len][++list[len][0]]=i;
28     }
29     //for(int i=1;i<=20;++i) printf("%d %d
",i,list[i][0]);
30 }
31 int main()
32 {
33     //freopen("numstring10.in","r",stdin);
34     //freopen("disappear.out","w",stdout);
35     //int st=clock();
36     init();
37     cin>>n;
38     for(int i=1;i<=n;++i){
39         scanf("%s",s);
40         ans+=check();
41     }
42     cout<<ans<<endl;
43     //cout<<clock()-st;
44     return 0;
45 }

  打表的部分参考前一个程序,这里的优化是把字符串根据长度分类,这样只用查找相同长度的目标串,可以水到100,灵感来源于哈希值,这里的len==key(这道题顺便为没学哈希的同学打一点基础)。当然我也了解到可以用“-”作为分割线,这样查找范围变小了好多;然后好像有写strcmp胡搞过的(???)等等(不管啦 反正就是个暴力题)。

写在后面

  第一次出题没有什么经验,而且比较水,搞了好久才弄完善。冬令营把题面搞出来,回家才学会出数据,这个解题报告就拖到开学了(中间还经历了一段痛苦不堪的补gan作业)。感谢Wahacer把最佳出题人赏赐给小的QAQ 有点承受不起啊(毕竟题这么水)……

  12mango退役快乐~~~

原文地址:https://www.cnblogs.com/12mango/p/8473650.html