您的位置:首页 > 其它

【蒻爆了的NOIP系列--普及组复赛】(2)NOIP2011普及组复赛题解

2016-09-03 19:38 597 查看
这只是一个作业,如果有帮到您的,我只能说。。。这不科学。。。

————————————华丽的分割线————————————

第一题:



很有趣的一道题。。。经典做法是字符串读入去头尾0记符号然后乱搞。。。不过我又机智的发明了膜(模)法。。。

下面是代码(主程序巨短)

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#define ci const int
#define ri register int
#define ll long long
#define reg register
#define boom return
#define cmax(a,b) (a)>(b)?(a):(b)
#define cmin(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(i=a;i<b;i++)
using namespace std;

int a;
int main()
{
int i;

scanf("%d",&a);
while(!(a%10))a/=10;
if(a<0)printf("-");
while(a!=0)printf("%d",abs(a%10)),a/=10;
boom 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌


————————————华丽的分割线————————————

第二题:





又是一道恶心死人的字符串题。。。首先我们要把他们全改成小写。。。

推荐语句:

for(i=0;i<wlen;i++)if(word[i]>='A'&&word[i]<='Z')word[i]+=32;
for(i=0;i<slen;i++)if(sen[i]>='A'&&sen[i]<='Z')sen[i]+=32;


然后遇到空格就一个字一个字判 把。。。

不过注意判完还要判下一个是不是空格。。

要不然像这个数据:

To
To be or not tobeisaquestion


就狗了

下面是程序

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#define ci const int
#define ri register int
#define ll long long
#define reg register
#define boom return
#define cmax(a,b) (a)>(b)?(a):(b)
#define cmin(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(i=a;i<b;i++)
using namespace std;

int wlen,slen,ans,first=-1;
char word[15],sen[1000086];
int pd(int i)
{
int j;
for(j=0;j<wlen;j++)
if(word[j]!=sen[i+j])return 0;
return ((sen[i+j]==' '||sen[i+j]=='\0')?1:0);
}
int main()
{
int i;

gets(word),gets(sen);
wlen=strlen(word),slen=strlen(sen);
for(i=0;i<wlen;i++)if(word[i]>='A'&&word[i]<='Z')word[i]+=32;
for(i=0;i<slen;i++)if(sen[i]>='A'&&sen[i]<='Z')sen[i]+=32;
//  for(i=0;i<wlen;i++)printf("%d ",word[i]);printf("\n");
//  for(i=0;i<slen;i++)printf("%d ",sen[i]);printf("\n");
for(i=0;i<slen&&(sen[i]<'a'||sen[i]>'z');i++);
if(pd(i)){ans++;if(first<0)first=i;}
for(;i<slen-wlen-1;i++)
{
if(sen[i]==' '&&pd(i+1))
{
ans++;
if(first<0)first=i+1;
}
}
if(first<0)printf("-1");
else printf("%d %d",ans,first);
boom 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌


————————————华丽的分割线————————————

第三题:





经典的瑞士轮,这道题一开始第一个思路就是每轮进行操作然后sort一遍

不过要是这样子,数据会让你刚好T掉。。。

所以我们需要常数优化~~~~

怎么优化呢?

首先可以看到每轮操作后每个选手分数要么+1要么不变

于是愉快的使用归并排序

a辣!!!

代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#define ci const int
#define ri register int
#define ll long long
#define reg register
#define boom return
#define cmax(a,b) (a)>(b)?(a):(b)
#define cmin(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(i=a;i<b;i++)
using namespace std;

ci MAXN=200086;
struct Player
{
int num,s,w;
}a[MAXN],b[MAXN],ans[MAXN];
int n,r,q;
bool pd(Player a,Player b)
{return (a.s==b.s)?(a.num<b.num):(a.s>b.s);}
void solve()
{
int x=1,y=1,z;
for (z=1;z<=n*2;z+=2)
if (ans[z].w>ans[z+1].w)ans[z].s++,a[x++]=ans[z],b[y++]=ans[z+1];
else ans[z+1].s++,a[x++]=ans[z+1],b[y++]=ans[z];
int i=1,j=1,k=1;
while(i<x&&j<y)
if(pd(a[i],b[j]))ans[k++]=a[i++];
else ans[k++]=b[j++];
while(i<x)ans[k++]=a[i++];
while(j<y)ans[k++]=b[j++];
}
int main()
{
int i;

scanf("%d%d%d",&n,&r,&q);
for(i=1;i<=n*2;i++)
scanf("%d",&ans[i].s),ans[i].num=i;
for (i=1;i<=n*2;i++)scanf("%d",&ans[i].w);
sort(ans+1,ans+1+2*n,pd);
for (i=1;i<=r;i++)solve();
printf("%d\n",ans[q].num);
return 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌


————————————华丽的分割线————————————

第四题:





这题很。。。恶心。。。

首先本人第一个想法是把算式用加号分开然后遇到括号拆掉继续递归。。。

然后发现没办法算方案数就。。。

第二个方法:dp

学长讲这是dp?qwq

这道题的正解原来是这样纸的。。。

首先把表达式加_并转后缀

然后dp。。。

首先用一个栈,每遇到一个数就入栈,遇到运算符把栈顶删了dp

状态:f[i][j]表示栈顶为i时答案为j的方案数

另外遇到数入栈时可能会覆盖原来的答案但是没卵用。

状态转移方橙:

遇到+:

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;


遇到乘相反qwq

就完结了。。。

代码巨长:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#include <stack>
#define ci const int
#define ri register int
#define ll long long
#define reg register
#define boom return
#define cmax(a,b) (a)>(b)?(a):(b)
#define cmin(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(i=a;i<b;i++)
using namespace std;

ci MAXN=100086;
int i,j,n,m,f[MAXN][2];
string s,w_c;
char str[MAXN],first[3]={'(','+','*'};
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 Change()
{
int i;
char t;
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]!=')' && str[i-1] != ')')
{
s.push_back('_');
s.push_back(str[i]);
}
else s.push_back(str[i]);
}
if(s.at(s.size()-1)!=')') s.push_back('_');
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())&& OPS(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();
op.pop();
}
}
}
while(!op.empty())
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);
Change();
work();
return 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌


(这个程序是学神写的我只是找了些错误。。。)

————————————华丽的分割线————————————

xiaoyao24256大学神访问量过40^2辣!!!膜膜膜
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: