高信息学奥赛模拟考试二十八Word文档下载推荐.docx
《高信息学奥赛模拟考试二十八Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《高信息学奥赛模拟考试二十八Word文档下载推荐.docx(16页珍藏版)》请在冰豆网上搜索。
2.路线只会在端点处改变方向
枚举任意两端点求出所有可能的端点间连线
-判断线段是否相交
使用最短路算法求解
-以出入口和端点为点
-以端点间的连线为边
参考程序:
#include<
iostream>
cstdio>
cmath>
#defineeps1e-8
#defineinf100000000
usingnamespacestd;
structWall{
doublex;
doubley[6];
}wall[20];
doubledist[80][80];
doublexmult(doublex0,doubley0,doublex1,doubley1,doublex2,doubley2){
return(x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
}
intdblcmp(doublea){
if(fabs(a)<
eps)return0;
return(a>
0)?
1:
-1;
boolCross(doublex0,doubley0,doublex1,doubley1,doublex2,doubley2,doublex3,doubley3){
return(dblcmp(xmult(x0,y0,x2,y2,x3,y3))^dblcmp(xmult(x1,y1,x2,y2,x3,y3)))==-2&
&
(dblcmp(xmult(x2,y2,x0,y0,x1,y1))^dblcmp(xmult(x3,y3,x0,y0,x1,y1)))==-2;
boolDirect(inti,intj,intp,intq){//判断从墙i的第j个点到墙p第q个点是否直达
intk,l;
for(k=i+1;
k<
p;
k++){
for(l=0;
l<
6;
l+=2)
if(Cross(wall[i].x,wall[i].y[j],wall[p].x,wall[p].y[q],
wall[k].x,wall[k].y[l],wall[k].x,wall[k].y[l+1]))
returnfalse;
}
returntrue;
inlinedoubleDist(doublex1,doubley1,doublex2,doubley2){
returnsqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
};
typedefdoubleelem_t;
doubledijkstra(intn){
intv[81],i,j,k;
doublemin[81];
for(i=0;
i<
=n;
i++)
min[i]=inf,v[i]=0;
for(min[0]=0,j=0;
j<
j++){
for(k=-1,i=0;
if(!
v[i]&
(k==-1||min[i]<
min[k]))
k=i;
for(v[k]=1,i=0;
min[k]+dist[k][i]<
min[i])
min[i]=min[k]+dist[k][i];
returnmin[n];
intmain(){
freopen("
door.in"
"
r"
stdin);
door.out"
w"
stdout);
intn,i,j,k,l;
wall[0].x=0;
wall[0].y[0]=5;
intttt=0;
scanf("
%d"
&
n);
while(ttt==0){
ttt=1;
for(i=0;
i<
=n*4+1;
i++)
for(j=0;
j<
j++)
dist[i][j]=inf;
wall[n+1].x=10;
wall[n+1].y[1]=5;
boolcon=true;
for(i=1;
=n;
i++){
scanf("
%lf"
wall[i].x);
for(j=1;
5;
wall[i].y[j]);
if((wall[i].y[1]>
5)||(wall[i].y[4]<
5)||(wall[i].y[2]<
5&
wall[i].y[3]>
5))
con=false;
wall[i].y[0]=0;
wall[i].y[5]=10;
if(con){
puts("
10.00"
);
continue;
j++){
if(i<
n)
for(k=1;
k++)
dist[i*4+j-4][i*4+k]=Dist(wall[i].x,wall[i].y[j],wall[i+1].x,wall[i+1].y[k]);
if(Direct(0,0,i,j))
dist[0][i*4+j-4]=Dist(0,5,wall[i].x,wall[i].y[j]);
if(Direct(i,j,n+1,1))
dist[i*4+j-4][n*4+1]=Dist(wall[i].x,wall[i].y[j],10,5);
for(k=i+2;
for(l=1;
l++)
if(Direct(i,j,k,l))
dist[i*4+j-4][k*4+l-4]=Dist(wall[i].x,wall[i].y[j],wall[k].x,wall[k].y[l]);
printf("
%.2lf\n"
dijkstra(n*4+1));
return0;
广义斐波那契数列(sequence)
广义的斐波那契数列是指形如an=p*an-1+q*an-2的数列。
今给定数列的两系数p和q,以及数列的最前两项a1和a2,另给出两个整数n和m,试求数列的第n项an除以m的余数。
输入包含一行6个整数。
依次是p,q,a1,a2,n,m,其中在p,q,a1,a2整数范围内,n和m在长整数范围内。
输出包含一行一个整数,即an除以m的余数。
【输入样例】
1111107
【输出样例】
6
【样例说明】
数列第10项是55,除以7的余数为6。
方法1:
由于n巨大,从头开始一一推算数列的每一项是不可能的。
又由于m巨大,利用数列对m取余的余数循环性质也是不可能的。
而本题采用的算法是由原本的递推公式(数列中某项与前两项的关系),推导得出数列中某项和与其遥遥相隔的连续两项之间的关系(比如a100与a1,a2之间的关系)。
推导过程如下。
an=p*an-1+q*an-2
an=(p*p+q)*an-2+(p*q)*an-3
an=((p*p+q)*p+p*q)*an-3+((p*p+q)*q)*an-4
……
an=ck*an-k+dk*an-k-1
(其中c、d数列的递推公式是cn=p*cn-1+dn-1,dn=q*cn-1,c1=p,d1=q)
如此,我们由最初两项向后推算时每步的步长可以非常大,忽略中间的许多项,从而节省时间。
首先根据给定的p、q以及上述递推公式计算出c29999和d29999除以m的余数。
然后根据a1和a2,计算出第三项。
根据前三项以及开始时求出的c,d数列中那两项的余数,计算出a30001和a30002除以m的余数。
根据这两项的余数,又可计算出a30003除以m的余数。
这样就由起初的连续三项一下子推出30000项后的连续三项。
当n巨大时,用这样的方法不断向前推接近n,到与n的距离不足30000时再一项项推算过去,直到求出an出除以m的余数为止。
可以在给定的时间内完成。
方法2:
矩阵的快速幂(见资料)
#include<
inti,j,k,n,m,p,q;
longlonga,b,c,d,f[30005];
intmain()
{
freopen("
sequence.in"
sequence.out"
cin>
>
p>
q>
f[1]>
f[2]>
n>
m;
p=p%m;
q=q%m;
f[1]=f[1]%m;
f[2]=f[2]%m;
f[3]=(p*f[2]+q*f[1])%m;
a=p;
b=q;
for(i=2;
=29999;
{
c=(p*a+b)%m;
d=(q*a)%m;
a=c;
b=d;
while(n>
30000)
n-=30000;
f[1]=(a*f[2]+b*f[1])%m;
f[2]=(a*f[3]+b*f[2])%m;
for(i=4;
f[i]=(p*f[i-1]+q*f[i-2])%m;
cout<
<
f[n];
fclose(stdin);
fclose(stdout);
车的放置(place)
有下面这样的一个网格棋盘,a,b,c,d表示了对应边长度,也就是对应格子数。
当a=b=c=d=2时,对应下面这样一个棋盘
要在这个棋盘上放K个相互不攻击的车,也就是这K个车没有两个车在同一行,也没有两个车在同一列,问有多少种方案。
同样只需要输出答案mod100003后的结果。
输入文件place.in的第1行为有5个非负整数a,b,c,d和k。
输出文件place.out包括1个正整数,为答案mod100003后的结果。
22222
38
【数据规模与约定】
对于部分数据,有b=0;
对于部分数据,有a,b,c,d≤4。
对于100%的数据,a,b,c,d,k≤1000,且保证了至少有一种可行方案。
在一个N×
M的棋盘中,放K个相互不攻击的车的方案数
N行中选K行放车,方案数C(N,K)
变成一个K×
M的棋盘,接下来这K行中,每一行放一个车,车的列不能相同,即列构成了M取K的排列,方案数P(N,K)
总方案数C(N,K)×
P(M,K)
考虑原棋盘
先在上部(a×
b)放i个车,剩下K–i个车放在下部((a+c)×
d)
在a×
b放i个车方案数C(a,i)×
P(b,i)
下部有i列不能放车,则等价于一个(a+c–i)×
d的一个棋盘
放K–i个车方案数C((a+c–i,K–i)×
P(d,K–i)
总C(a,i)×
P(b,i)×
C((a+c–i,K–i)×
枚举i,求和即为答案
string>
cstring>
vector>
map>
algorithm>
constintMXN=2002;
inta,b,c,d,k;
longlongC[MXN][MXN];
longlongP[MXN][MXN];
longlongans;
longlongcalc(intn,intm,intk){
//if(k>
n||k>
m)return0;
returnC[n][k]*P[m][k]%100003;
intmain(){
place.in"
"
stdin);
place.out"
stdout);
memset(C,0,sizeof(C));
memset(P,0,sizeof(P));
for(inti=0;
i<
MXN;
i++)
for(intj=0;
j<
=i;
j++){
if(j==0||j==i){
C[i][j]=1;
}else{
C[i][j]=(C[i-1][j]+C[i-1][j-1])%100003;
i++){
P[i][0]=1;
for(intj=1;
j++)
P[i][j]=P[i][j-1]*(i-j+1)%100003;
cin>
a>
b>
c>
d>
k;
ans=0;
for(inti=0;
=min(min(a,b),k);
ans+=calc(a,b,i)*calc(a+c-i,d,k-i)%100003;
ans%=100003;
cout<
ans<
endl;
排序(sort)
一个不同的值的升序排序数列指的是一个从左到右元素依次增大的序列,例如,一个有序的数列A,B,C,D表示A<
B,B<
C,C<
D。
在这道题中,我们将给你一系列形如A<
B的关系,并要求你判断是否能够根据这些关系确定这个数列的顺序。
第一行有两个整数n,m,n表示需要排序的元素数量,2<
=n<
=26,第1到n个元素将用大写的A,B,C,D....表示。
m表示将给出的形如A<
B的关系的数量。
接下来有m行,每行有3个字符,分别为一个大写字母,一个<
符号,一个大写字母,表示两个元素之间的关系。
若根据前x个关系即可确定这n个元素的顺序yyy..y(如ABC),输出
Sortedsequencedeterminedafterxxxrelations:
yyy...y.
若根据前x个关系即发现存在矛盾(如A<
A),输出
Inconsistencyfoundafter2relations.
若根据这m个关系无法确定这n个元素的顺序,输出
Sortedsequencecannotbedetermined.
(提示:
确定n个元素的顺序后即可结束程序,可以不用考虑确定顺序之后出现矛盾的情况)
46
A<
B
C
B<
C<
D
2:
32
A
3:
261
Z
Sortedsequencedeterminedafter4relations:
ABCD.
Sortedsequencecannotbedetermined.
将每个元素作为一个点
每个关系X<
Y对应一条X到Y的边
使用拓扑排序判断当前图是否存在确定的顺序
若存在环,则存在矛盾
最多需进行m次拓扑排序
cstdlib>
#defineFOR(i,a,b)for(inti=a;
=b;
#defineMST(a,b)memset(a,b,sizeof(a))
#defineMAXN30
#defineMAXM1000
intn,m,ue[MAXM],ve[MAXM],b[MAXM];
inttot,first[MAXN],next[MAXM];
voidadd(intu,intv)
ue[++tot]=u;
ve[tot]=v;
next[tot]=first[u];
first[u]=tot;
voidinit()
MST(first,0);
chara,b;
tot=0;
FOR(i,1,m)
%c<
%c\n"
a,&
b);
intu=a-'
A'
+1,v=b-'
+1;
add(u,v);
intd0[MAXN],d[MAXN];
intq[MAXN],l,r;
inttryt()//-1失败0成功1唯一
intl=1,r=0;
FOR(i,1,n)d[i]=d0[i];
intqd=1;
FOR(i,1,n)if(d[i]==0)q[++r]=i;
while(l<
=r)
if(l<
r)qd=0;
intu=q[l++];
for(intp=first[u];
p!
=0;
p=next[p])
if(b[p])
intv=ve[p];
d[v]--;
if(d[v]==0)q[++r]=v;
if(r<
n)return-1;
if(qd)return1;
voidwork()
MST(d0,0);
MST(b,0);
d0[ve[i]]++;
b[i]=1;
intt=tryt();
if(t==-1)
Inconsistencyfoundafter%drelations.\n"
i);
return;
if(t==1)
Sortedsequencedeterminedafter%drelations:
"
FOR(j,1,n)printf("
%c"
q[j]+'
-1);
.\n"
Sortedsequencecannotbedetermined.\n"
sort.in"
sort.out"
%d%d\n"
n,&
m);
//while(!
((n==0)&
(m==0)))
//{
init();
work();
//scanf("
//}