[考试]NOIP2015模拟题2
// 此博文为迁移而来,写于2015年7月22日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w72i.html
1、总结
向总表示今天的题目简单些,恩我觉得我又单纯了。今天的分数略低啊,第三题的动规只有10分,第一题的暴力也TLE了一堆,最后就剩下个150分了。
2、题解
T1 坐船问题(TAG:结论题)
简直就是一道结论题啊!这道题不存在什么算法。最开始想到的是二分图匹配,但是过于繁琐,而且已经证出存在反例。首先对于两个对象A和B,如果他们姓相同或者名相同,则将两者之间连一条边,任何相对之间存在姓相同或名相同关系的点,便会组成一个连通块,通过对其中的分析,可以得出其中的结论。具体的我没有做出来,大家可以看看解题报告中的一段话,代码就不上了。
T2 多边形划分问题(TAG:动态规划)
【P.S 标题有误,特此提醒】
一道动态规划题目,核心在于对于多边形的每一个顶点进行编号,根据n边形由n-2个三角形组成的原理,可以设计出状态。
代码:
---------------------------------------------------------------------------------------------------
#include cstdio
#include cstring
#include cstdio
#include cstring
#define MAXN 105
#define MOD 100000
#define INF 1<<30
typedef long long arr[MAXN];
long long max(long long a,long long b) { return (a>b)?a:b; }
arr f[MAXN][MAXN],a,s1,s2,s3;
long long n;
long long n;
void mark(arr &c)
{
for (int i=1;i<=c[0];i++)
{
c[i+1]+=c[i]/MOD;
c[i]%=MOD;
}
while (c[c[0]+1])
{
c[0]++;
c[c[0]+1]+=c[c[0]]/MOD;
c[c[0]]%=MOD;
}
}
{
for (int i=1;i<=c[0];i++)
{
c[i+1]+=c[i]/MOD;
c[i]%=MOD;
}
while (c[c[0]+1])
{
c[0]++;
c[c[0]+1]+=c[c[0]]/MOD;
c[c[0]]%=MOD;
}
}
void multi(long long a1,long long a2,long long a3,arr &s)
{
memset(s,0,sizeof(s));
s[0]=s[1]=1;
for (int i=1;i<=s[0];i++) s[i]*=a1; mark(s);
for (int i=1;i<=s[0];i++) s[i]*=a2; mark(s);
for (int i=1;i<=s[0];i++) s[i]*=a3; mark(s);
}
{
memset(s,0,sizeof(s));
s[0]=s[1]=1;
for (int i=1;i<=s[0];i++) s[i]*=a1; mark(s);
for (int i=1;i<=s[0];i++) s[i]*=a2; mark(s);
for (int i=1;i<=s[0];i++) s[i]*=a3; mark(s);
}
void addVal(arr a,arr b,arr &c)
{
memset(c,0,sizeof(c));
c[0]=max(a[0],b[0]);
for (int i=1;i<=c[0];i++) c[i]=a[i]+b[i];
mark(c);
}
{
memset(c,0,sizeof(c));
c[0]=max(a[0],b[0]);
for (int i=1;i<=c[0];i++) c[i]=a[i]+b[i];
mark(c);
}
int check(arr a,arr b)
{
if (a[0]<b[0]) return 0;
if (a[0]>b[0]) return 1;
for (int i=a[0];i>=1;i--)
if (a[i]
else if (a[i]>b[i]) return 1;
return 0;
}
{
if (a[0]<b[0]) return 0;
if (a[0]>b[0]) return 1;
for (int i=a[0];i>=1;i--)
if (a[i]
else if (a[i]>b[i]) return 1;
return 0;
}
int main()
{
freopen("polygon.in","r",stdin);
freopen("polygon.out","w",stdout);
scanf("%I64d",&n);
for (int i=1;i<=n;i++) scanf("%I64d",&a[i]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) f[i][j][0]=1;
for (int i=n-2;i>=1;i--)
for (int j=i+2;j<=n;j++)
{
f[i][j][0]=INF;
for (int k=i+1;k<=j-1;k++)
{
multi(a[i],a[k],a[j],s1);
addVal(f[i][k],f[k][j],s2);
addVal(s1,s2,s3);
if (check(f[i][j],s3)) memcpy(f[i][j],s3,sizeof(f[i][j]));
}
}
printf("%I64d",f[1][n][f[1][n][0]]);
for (int i=f[1][n][0]-1;i>=1;i--) printf("I64d",f[1][n][i]);
printf("\n");
}
{
freopen("polygon.in","r",stdin);
freopen("polygon.out","w",stdout);
scanf("%I64d",&n);
for (int i=1;i<=n;i++) scanf("%I64d",&a[i]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) f[i][j][0]=1;
for (int i=n-2;i>=1;i--)
for (int j=i+2;j<=n;j++)
{
f[i][j][0]=INF;
for (int k=i+1;k<=j-1;k++)
{
multi(a[i],a[k],a[j],s1);
addVal(f[i][k],f[k][j],s2);
addVal(s1,s2,s3);
if (check(f[i][j],s3)) memcpy(f[i][j],s3,sizeof(f[i][j]));
}
}
printf("%I64d",f[1][n][f[1][n][0]]);
for (int i=f[1][n][0]-1;i>=1;i--) printf("I64d",f[1][n][i]);
printf("\n");
}
----------------------------------------------------------------------------------------------------
T3 系统可靠性问题(TAG:动态规划)
这道题是比较简单的完全背包问题了,但是由于考试时候匆匆忙忙,写萎了,结果只得了10分。含有一个值得注意的地方,读入的时候,对于每一个零件,题目中并没有给出他的备用零件个数选择有多少种方式,所以需要在读入时判断回车符。
代码略。
T4 重复子串问题(TAG:KMP算法)
暴力大法好!有人打了个暴力就A了真是不能忍。。。我开始想过这种做法,但是看到数据范围后就弃疗了,然而并不清楚为什么可以A了。先说说暴力的做法吧:对于每一个字母数字组合,记录其曾经出现过的位置,依次进行比较,得到重复串后判断是否相连即可。正解的话是江哥跟我们讲的,可以巧妙利用KMP算法的fail指针。
代码略。