【用膝盖写代码系列】(2):NOIP2011普及组复赛题目详解
2016-08-22 23:01
501 查看
这里是NOIP2011的急救现场,我已经准备好了救护车。
那么我们从第一题开始
第一题:数字反转
题意简述:给一个不超过10位的数(包括负号),输出这个数的反转。
(如:123,输出321)
陷阱提示:记得要预处理负号以及前导0
我对它的类型评估: 模拟
思路描述:这道题十分简单,用字符串读入,预处理负号,然后从后往前for,处理前导0,就可AC。
我的代码:
洛谷原题:http://www.luogu.org/problem/show?pid=1307
第一题完。
第二题:统计单词数
(本人的内心:啊!!!!这是谁出的题目!拖出去大阿十遍!)
题目简述:给定一个单词以及一篇文章,求这个单词在文章的出现次数以及第一次出现的位置
陷阱提示:要注意全字匹配,不能单单截取单词的一部分!
我对它的类型评估:字符串操作、模拟
思路描述:这道题好坑啊TAT,主要原因是它的文章是有纯空格单词的…..这道题的思想就是:先把字母大小写统一(本题不区分大小写,所以要统一),然后枚举每一个文章中的单词,与原本的单词进行比较。
枚举的过程:枚举每一个文章中的字母,然后从当前字母A开始向后枚举所需求单词B的长度,然后A与B比较,如果完全相同,然后再判断单词A的前、后是否都是空格(否则有可能出现枚举一个单词一部分的情况),如果是第一次更新,就把答案设置为枚举时所循环的值(一般是i),此做法能AC、
我的代码
洛谷原题:http://www.luogu.org/problem/show?pid=1308
第二题总结:每一道题都有一个陷阱,切记在考场上要考虑到可能出现的数据!
第二题完。
第三题:瑞士轮
题意简述:给定n个人的实力以及分数,每一次比赛都让相差一名的人进行比赛(第一与第二,第三与第四,以此类推),赢的人得1分,然后重新排名。先给出人数n*2,场数r,以及q,求r场后排名q的选手编号是多少
陷阱提示:此题用sort会TLE!
数据范围:对于100%的数据,
1 ≤ N ≤ 100,000,1 ≤ R ≤ 50,1 ≤ Q ≤ 2N,0 ≤ s1, s2, …, s2n≤108,1 ≤w1, w2 , …, w2n≤ 108
我对它的类型评估:模拟
*本题涉及函数:*merge
这个函数的作用是合并数组A与数组B,若A、B是有序的,即完成一次归并排序。
思路描述:这道题其实就如题面描述一般进行模拟即可,记住每一次比赛模拟结束之后,记录一下成功者与失败者,最后用merge来合并(因为这两个数组一定有序)
我的代码
洛谷原题:http://www.luogu.org/problem/show?pid=1309
第三题完。
第四题:表达式的值
题意简述:
对于1 位二进制变量定义两种运算:
![](http://cdnv2.luogu.org/upload/pic/99.png)
运算的优先级是:
先计算括号内的,再计算括号外的。
“× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算。例如:计算表达式A⊕B × C时,先计算 B × C,其结果再与 A 做⊕运算。
现给定一个未完成的表达式,例如+(*_),请你在横线处填入数字0 或者1 ,请问有多少种填法可以使得表达式的值为0 。
陷阱提示:无
我对它的类型评估:栈、动态规划
思路描述:
这道题是我做过最难的NOIP题目。
这道题的步骤很简单:
①:将式子从+(x)的形式变成的带有空的形式
②:将式子从中缀表达式化作后缀表达式
③:进行动态规划
状态转移方程:
设f[i][0]表示第i个空,能填0,f[i][1]表示第i个空,能填1
那么转移方程就出来了:
我的代码:
洛谷原题:http://www.luogu.org/problem/show?pid=1310
第四题完。
各位再见,我开救护车去飙车了88
那么我们从第一题开始
第一题:数字反转
题意简述:给一个不超过10位的数(包括负号),输出这个数的反转。
(如:123,输出321)
陷阱提示:记得要预处理负号以及前导0
我对它的类型评估: 模拟
思路描述:这道题十分简单,用字符串读入,预处理负号,然后从后往前for,处理前导0,就可AC。
我的代码:
#include <cstdio> #include <cstring> int main(){ int i,j,n,m; char a[13]; scanf("%s",&a); int len = strlen(a); if(len == 1 && a[len-1] == 0) { printf("0"); return 0; } if(a[0] == '-') printf("-"); len--; // printf("a[len] = %c\n",a[len]); while(a[len] == '0') len--; for(i=len;i>=0;i--) if(a[i] >= '0' && a[i] <= '9') printf("%c",a[i]); }
洛谷原题:http://www.luogu.org/problem/show?pid=1307
第一题完。
第二题:统计单词数
(本人的内心:啊!!!!这是谁出的题目!拖出去大阿十遍!)
题目简述:给定一个单词以及一篇文章,求这个单词在文章的出现次数以及第一次出现的位置
陷阱提示:要注意全字匹配,不能单单截取单词的一部分!
我对它的类型评估:字符串操作、模拟
思路描述:这道题好坑啊TAT,主要原因是它的文章是有纯空格单词的…..这道题的思想就是:先把字母大小写统一(本题不区分大小写,所以要统一),然后枚举每一个文章中的单词,与原本的单词进行比较。
枚举的过程:枚举每一个文章中的字母,然后从当前字母A开始向后枚举所需求单词B的长度,然后A与B比较,如果完全相同,然后再判断单词A的前、后是否都是空格(否则有可能出现枚举一个单词一部分的情况),如果是第一次更新,就把答案设置为枚举时所循环的值(一般是i),此做法能AC、
我的代码
#include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> using namespace std; int main(){ int i,j,n,m; char word[12]; char text[1000001]; //freopen("a.in","r",stdin); gets(word); gets(text); int lenw = strlen(word),lent = strlen(text); int count = 0,cur = -1; int sum=0; bool flag = true; for(i=0;i<lenw;i++) { if(word[i] >= 'a' && word[i] <= 'z') word[i] = word[i]&~(1<<5);//小写转大写 } for(i=0;i<lent;i++) { if(text[i] >= 'a' && text[i] <= 'z') text[i] = text[i]&~(1<<5);//同上 } for(i=0;i<=lent;i++){ for(j=0;j<lenw;j++){ if(text[i+j]!= word[j]) flag = false; } if(flag) { if((text[i-1] == ' ' && text[i+lenw] == ' ')|| i==0){ count++; if(cur==-1) { cur = i; } } } flag = true; } if(cur==-1) puts("-1"); else printf("%d %d",count,cur); return 0; }
洛谷原题:http://www.luogu.org/problem/show?pid=1308
第二题总结:每一道题都有一个陷阱,切记在考场上要考虑到可能出现的数据!
第二题完。
第三题:瑞士轮
题意简述:给定n个人的实力以及分数,每一次比赛都让相差一名的人进行比赛(第一与第二,第三与第四,以此类推),赢的人得1分,然后重新排名。先给出人数n*2,场数r,以及q,求r场后排名q的选手编号是多少
陷阱提示:此题用sort会TLE!
数据范围:对于100%的数据,
1 ≤ N ≤ 100,000,1 ≤ R ≤ 50,1 ≤ Q ≤ 2N,0 ≤ s1, s2, …, s2n≤108,1 ≤w1, w2 , …, w2n≤ 108
我对它的类型评估:模拟
*本题涉及函数:*merge
merge(数组A,A的结尾,数组B,B的结尾,输出数组C,交换函数)
这个函数的作用是合并数组A与数组B,若A、B是有序的,即完成一次归并排序。
思路描述:这道题其实就如题面描述一般进行模拟即可,记住每一次比赛模拟结束之后,记录一下成功者与失败者,最后用merge来合并(因为这两个数组一定有序)
我的代码
#include <cstdio> #include <algorithm> #include <queue> struct Player{ int score,num,val; }player[200002]; bool cmp(Player a,Player b){ if(a.score == b.score) return a.num < b.num; else return a.score > b.score; } Player winner[200001],loser[200001]; int main(){ int i,j,n,m,q,r,winner_count=0,loser_count=0; scanf("%d%d%d",&n,&r,&q); for(i=1;i<=n*2;i++){ scanf("%d",&player[i].score); player[i].num = i; } for(i=1;i<=n*2;i++) scanf("%d",&player[i].val); std::sort(player+1,player+1+(2*n),cmp); for(i=1;i<=r;i++){ winner_count = loser_count = 0; for(j=1;j<=n*2;j+=2){ if(player[j].val > player[j+1].val) { player[j].score++; winner[winner_count++] = player[j]; loser[loser_count++] = player[j+1]; } else{ player[j+1].score++; winner[winner_count++] = player[j+1]; loser[loser_count++] = player[j]; } } std::merge(winner,winner+winner_count,loser,loser+loser_count,player+1,cmp); } printf("%d",player[q].num); }
洛谷原题:http://www.luogu.org/problem/show?pid=1309
第三题完。
第四题:表达式的值
题意简述:
对于1 位二进制变量定义两种运算:
![](http://cdnv2.luogu.org/upload/pic/99.png)
运算的优先级是:
先计算括号内的,再计算括号外的。
“× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算。例如:计算表达式A⊕B × C时,先计算 B × C,其结果再与 A 做⊕运算。
现给定一个未完成的表达式,例如+(*_),请你在横线处填入数字0 或者1 ,请问有多少种填法可以使得表达式的值为0 。
陷阱提示:无
我对它的类型评估:栈、动态规划
思路描述:
这道题是我做过最难的NOIP题目。
这道题的步骤很简单:
①:将式子从+(x)的形式变成的带有空的形式
②:将式子从中缀表达式化作后缀表达式
③:进行动态规划
状态转移方程:
设f[i][0]表示第i个空,能填0,f[i][1]表示第i个空,能填1
那么转移方程就出来了:
switch(w_c[i]){ case '+':{ f[top-1][1] = (f[top][0] * f[top-1][1] + f[top][1] * f[top-1][0] + f[top][1] * f[top-1][1])%10007; f[top-1][0] = (f[top][0] * f[top-1][0]) % 10007; break; } case '*':{ f[top-1][0] = (f[top][0] * f[top-1][1] + f[top][1] * f[top-1][0] + f[top][0] * f[top-1][0])%10007; f[top-1][1] = (f[top][1] * f[top-1][1]) % 10007; break; } }
我的代码:
#include <cstdio>
#include <stack>
#include <iostream>
using namespace std;
int i,j,n,m;
string s,w_c;
char str[100001],first[3] = {'(','+','*'};
int f[100001][2];
stack<char> op;
int OPS(char a){
int i;
for(i=0;i<3;i++){
if(a == first[i]) return i;
}
return -1;
}
inline void ChangeS(){
int i;
for(i=0;i<n;i++){
if(str[i] == '(') s.push_back(str[i]);
else if(str[i] == ')' && str[i-1] != ')') s+="_)";
else if(str[i]!=')') {
s.push_back('_');
s.push_back(str[i]);
}
else s.push_back(str[i]);
if(s.at(s.size()-1)!=')') s.push_back(str[i]);
}
}
inline void ChangeE(){
size_t i;
char t;
for(i=0;i<s.size();i++){
t = s.at(i);
if(t == '_') w_c.push_back(t);
else {if(t != ')'){
if(t == '(') op.push(t);
else if(op.empty()) op.push(t);
else {
while(!op.empty() && op.top() >= OPS(t)){
w_c.push_back(op.top());
op.pop();
}
op.push(t);
}
}
else
while(!op.empty() && op.top()!='('){
w_c.push_back(op.top());
op.pop();
}
}
}
}
void work(){
size_t i,top(0);
size_t l = w_c.size();
for(i=0;i<l;i++) {
if(w_c[i] == '_'){
f[top][0] = f[top][1] = 1;
top++;
}
else{
--top;
switch(w_c[i]){ case '+':{ f[top-1][1] = (f[top][0] * f[top-1][1] + f[top][1] * f[top-1][0] + f[top][1] * f[top-1][1])%10007; f[top-1][0] = (f[top][0] * f[top-1][0]) % 10007; break; } case '*':{ f[top-1][0] = (f[top][0] * f[top-1][1] + f[top][1] * f[top-1][0] + f[top][0] * f[top-1][0])%10007; f[top-1][1] = (f[top][1] * f[top-1][1]) % 10007; break; } }
}
}
printf("%d",f[top-1][0]);
}
int main(){
scanf("%d",&n);
scanf("%s",&str);
ChangeS();
ChangeE();
work();
return 0;
}
洛谷原题:http://www.luogu.org/problem/show?pid=1310
第四题完。
各位再见,我开救护车去飙车了88
相关文章推荐
- 【用膝盖写代码系列】(2):NOIP2011普及组复赛详解
- 【用膝盖写代码系列】(5):NOIP2013普及组复赛详解
- 【用膝盖写代码系列】(1):NOIP2010普及组复赛详解
- 【用膝盖写代码系列】(3):NOIP2012普及组题目详解
- 【用膝盖写代码系列】(4):NOIP2014普及组复赛详解
- 【蒻爆了的NOIP系列--普及组复赛】(2)NOIP2011普及组复赛题解
- NOIP2011-普及组复赛模拟试题-第一题-NBA总冠军
- 竞赛题目讲解-【NOIP2000复赛 普及组】单词接龙
- NOIP2011-普及组复赛模拟试题-第二题-买票
- NOIP2016 普及组 总结+题目吐槽+代码+简单题解
- NOIP 2011 普及组 复赛 stat 统计单词数
- 这是我做的2015年noip普及组复赛第一题的代码,可以借鉴借鉴
- 【蒻爆了的NOIP系列--普及组复赛】(3)NOIP2012普及组复赛题解
- 【蒻爆了的NOIP系列--普及组复赛】(1)NOIP2010普及组复赛题解
- NOIP2011-普及组复赛-第二题-统计单词数
- 【蒻爆了的NOIP系列--普及组复赛】(4)NOIP2013普及组复赛题解
- 【蒻爆了的NOIP系列--普及组复赛】(5)NOIP2014普及组复赛题解
- NOIP 2011 普及组 复赛 reverse 数字反转
- 不高兴的津津 C语言题目详解 noip2004普及组第1题
- noip2011普及组复赛——数字反转