NOIP2008 提高组题解
作者:互联网
luogu对应题目T1 笨小猴、T2 火柴棒等式 、T3 传纸条 、T4 双栈排序 ,可以到luogu上查看更多题解。
T1 笨小猴 素数
给出一个单词,统计其中出现最多的字母出现的次数maxn,以及出现最少的字母的次数minn,如果maxn-minn是质数的话则作为一个Lucky Word..否则即为No Answer.
直接模拟即可
#include <stdio.h>
#include <string.h>
int count[27],max,min;
char s[200];
bool notprime[102];
int main()
{
freopen("word.in","r",stdin);
freopen("word.out","w",stdout);
gets(s);
memset(count,0,sizeof(count));
for (int i=0;s[i];i++)
count[s[i]-96]++;
min = 2147483647;
max = 0;
for (int i=1;i<=26;i++)
{
if (!count[i])
continue;
if (max<count[i])
max = count[i];
if (min>count[i])
min = count[i];
}
int j;
notprime[0] = true;
notprime[1] = true;
for (int i=2;i<=50;i++)
{
j = i*2;
while (j<=100)
{
notprime[j] = true;
j += i;
}
}
max -= min;
if (notprime[max])
{
printf("No Answer\n");
max = 0;
}
else
printf("Lucky Word\n");
printf("%d\n",max);
return 0;
}
T2 火柴棒等式 枚举
给你n(n<=24)根火柴棒,叫你拼出 "A + B = C"这样的等式,求方案数.
直接枚举A和B(事实证明只到3位数),事先预处理2000以内各个数所用的火柴数.直接枚举出解
#include <stdio.h>
#include <string.h>
int n,ans;
int c[2002]={6,2,5,5,4,5,6,3,7,6};
int main()
{
freopen("matches.in","r",stdin);
freopen("matches.out","w",stdout);
scanf("%d",&n);
for (int i=10;i<=1800;i++)
c[i] = c[i/10]+c[i%10];
n -= 4;ans = 0;
for (int i=0;i<=800;i++)
for (int j=0;j<=800;j++)
if (c[i]+c[j]+c[i+j]==n)
ans++;
printf("%d\n",ans);
return 0;
}
T3 传纸条 动态规划
给一个矩阵(左上角和右下角固定为0),从左上角走两次到右下角,两次走的路径不能有交集(即一个点不能被走两次),求两次走过的格子上的数的和最大是多少.(类似二取方格数.)
二取方格数很经典的题目了,于是便直接以 f[i][j][k][p] 表示第一条路径走到(i,j),第二条路径走到(k,p)所取到的数的最大值..转移方程就很好办了..同时注意判断两条路不要从同一个点转移过来就好了.
#include <stdio.h>
#include <string.h>
int a[52][52],f[52][52][52][52],n,m,ni,nj,nk,np;
int next[4][4]={0,-1,-1,0,-1,0,-1,0,0,-1,0,-1,-1,0,0,-1};
int main()
{
freopen("message.in","r",stdin);
freopen("message.out","w",stdout);
scanf("%d %d",&n,&m);
memset(f,0,sizeof(f));
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
for (int k=1;k<=n;k++)
for (int p=j;p<=m;p++)
for (int m=0;m<=3;m++)
{
ni = i + next[m][0];
nj = j + next[m][1];
nk = k + next[m][2];
np = p + next[m][3];
if ((ni!=nk)||(nj!=np))
if (f[i][j][k][p] < f[ni][nj][nk][np] + a[i][j] + a[k][p])
f[i][j][k][p] = f[ni][nj][nk][np] + a[i][j] + a[k][p];
}
printf("%d",f[n][m][n][m]);
return 0;
}
T4 双栈排序 二分图、栈
本题很难,有如下题意。
有两个队列和两个栈,分别命名为队列1(q1),队列2(q2),栈1(s1)和栈2(s2).最初的时候,q2,s1和s2都为空,而q1中有n个数(n<=1000),为1~n的某个排列.
现在支持如下四种操作:
a操作,将 q1的首元素提取出并加入s1的栈顶.
b操作,将s1的栈顶元素弹出并加入q1q2的队列尾.
c操作,将 q1的首元素提取出并加入s2的栈顶.
d操作,将s2的栈顶元素弹出并加入q1q2的队列尾.
请判断,是否可以经过一系列操作之后,使得q2中依次存储着1,2,3,…,n.如果可以,求出字典序最小的一个操作序列.
下面开始做题了
第一步需要解决的问题是,判断是否有解.
考虑对于任意两个数q1[i]和q1[j]来说,它们不能压入同一个栈中的充要条件是什么(注意没有必要使它们同时存在于同一个栈中,只是压入了同 一个栈).实际上,这个条件p是:存在一个k,使得i<j<k且q1[k]<q1[i]<q1[j].
首先证明充分性,即如果满足条件p,那么这两个数一定不能压入同一个栈.这个结论很显然,使用反证法可证.
假设这两个数压入了同一个栈,那么在压入q1[k]的时候栈内情况如下:
…q1[i]…q1[j]…
因为q1[k]比q1[i]和q1[j]都小,所以很显然,当q1[k]没有被弹出的时候,另外两个数也都不能被弹出(否则q2中的数字顺序就不是1,2,3,…,n了).
而之后,无论其它的数字在什么时候被弹出,q1[j]总是会在q1[i]之前弹出.而q1[j]>q1[i],这显然是不正确的.
接下来证明必要性.也就是,如果两个数不可以压入同一个栈,那么它们一定满足条件p.这里我们来证明它的逆否命题,也就是"如果不满足条件p,那么这两个数一定可以压入同一个栈."
不满足条件p有两种情况:一种是对于任意i<j<k且q1[i]<q1[j],q1[k]>q1[i];另一种是对于任意i<j,q1[i]>q1[j].
第一种情况下,很显然,在q1[k]被压入栈的时候,q1[i]已经被弹出栈.那么,q1[k]不会对q1[j]产生任何影响(这里可能有点乱,因为看起来,当q1[j]<q1[k]的时候,是会有影响的,但实际上,这还需要另一个数r,满足j<k<r且 q1[r]<q1[j]<q1[k],也就是证明充分性的时候所说的情况…而事实上我们现在并不考虑这个r,所以说q1[k]对q1[j]没有影响).="">
第二种情况下,我们可以发现这其实就是一个降序序列,所以所有数字都可以压入同一个栈.
这样,原命题的逆否命题得证,所以原命题得证.</q1[k]的时候,是会有影响的,但实际上,这还需要另一个数r,满足j<k<r且>
此时,条件p为q1[i]和q1[j]不能压入同一个栈的充要条件也得证.
这样,我们对所有的数对(i,j)满足1<=i<j<=n,检查是否存在i<j<k满足p1[k]< p1[i]
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
int a[maxn],color[maxn];
int s1[maxn],s2[maxn];
int n;
vector< vector<int> >G(maxn);
bool bfs(int s)
{
queue<int>q;
color[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(color[v]==0)color[v]=color[u]*-1,q.push(v);
else if(color[v]!=color[u]*-1)return false;
}
}
return true;
}
int main()
{
freopen("twostack.in","r",stdin);
freopen("twostack.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
int r=0;
for(int j=n;j>i;j--)
if(a[i]>a[j])
{
r=j;
break;
}
for(int j=i+1;j<r;j++)
if(a[i]<a[j])
{
G[i].push_back(j);
G[j].push_back(i);
}
}
int ok=1;
for(int i=1;i<=n;i++)
if(color[i]==0)
{
if(bfs(i))continue;
ok=0;
break;
}
if(ok==0)
{
printf("0");
return 0;
}
int cnt=1,tp1=0,tp2=0;
vector<char>v;
for(int i=1;i<=n;i++)
{
if(color[i]==1)
{
s1[++tp1]=a[i];
v.push_back('a');
}
else
{
s2[++tp2]=a[i];
v.push_back('c');
}
while(s1[tp1]==cnt||s2[tp2]==cnt)
{
if(s1[tp1]==cnt)
{
tp1--;
v.push_back('b');
}
else
{
tp2--;
v.push_back('d');
}
cnt++;
}
}
printf("%c",v[0]);
for(int i=1;i<v.size();i++)
printf(" %c",v[i]);
return 0;
}
标签:q1,压入,int,题解,提高,NOIP2008,52,maxn,include 来源: https://www.cnblogs.com/BobHuang/p/15363916.html