第一题:合理种植
大COS在氯铯石料场干了半年,受尽了劳苦,终于决定辞职。他来到表弟小cos的寒树中学,找到方克顺校长,希望寻个活干。于是他如愿以偿接到了一个任务……
美丽寒树中学种有许多寒树。方克顺希望校园无论从什么角度看都是满眼寒树,因此他不希望有三棵甚至更多寒树种在一条直线上。现在他把校园里n棵寒树的坐标都给了大COS,让他数出存在多少多树共线情况。(若一条直线上有三棵或以上的树,则算出现一个多树共线情况。)
这道题判重比较麻烦。枚举前两个点,算出斜率,第三个点和第二个点所在直线的斜率如果等于之前算出来的一、二两点的斜率,并且一、二、三三点都未用过,ans++,一、二、三三点标记未使用过。
代码:
#include<cstdio>
#include<iostream>
using namespace std;
int x[1005],y[1003];
bool b[1005][1005];
long long dis[1005][1005];
main()
{
freopen("plant.in","r",stdin);
freopen("plant.out","w",stdout);
int n,i,j,ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++)
{
if(x[i]!=x[j])dis[i][j]=((y[i]-y[j])*100000000LL)/(x[i]-x[j]); //经计算每个斜率至少到小数点后8为才不同
else dis[i][j]=1;
}
for(i=1;i<=n-2;i++)
{
for(j=i+1;j<=n-1;j++)
{
for(int l=j+1;l<=n;l++)
if(dis[i][j]==dis[j][l])
if(!b[i][j]&&!b[j][l]&&!b[i][l])
{
b[i][j]=true;b[j][l]=true;b[i][l]=true;
ans++;
}
else
{
b[i][j]=true;b[j][l]=true;b[i][l]=true;
}
}
}
printf("%d",ans);
}
第二题:排队
小sin所在的班有n名同学,正准备排成一列纵队,但他们不想按身高从矮到高排,那样太单调,太没个性。他们希望恰好有k对同学是高的在前,矮的在后,其余都是矮的在前,高的在后。如当n=5,k=3时,假设5人从矮到高分别标为1、2、3、4、5,则(1,5,2,3,4)、(2,3,1,5,4)、(3,1,4,2,5)都是可行的排法。小sin想知道总共有多少种可行排法。由于结果可能很大,请输出排法数mod 1799999的值。
动态规划,f[i][j]表示i个数,j对同学。从后往前推,如果在已有的四个数中插入第五个数,插在最后面的话对数不变,插在倒数第二个数与倒数第一个数中时对数加1(插入的数比原数列任何一个数都大),以此类推,得到递推关系式:
f[i][j]=f[i-1][j]+f[i-1][j-1]+……+f[i-1][j-i+1](若j-i+1<0,则到0停止)
代码:
#include<cstdio>
#include<cstdlib>
#include<ctime>
int f[102][5000];
int main()
{
freopen("lineup.in","r",stdin);
freopen("lineup.out","w",stdout);
int n,m,i;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
f[i][0]=1;f[i][1]=i-1;
}
for(i=1;i<=n;i++)
for(int j=2;j<=i*(i-1)/2;j++)
{
if(j+1>=i)
for(int k=j;k>=j+1-i;k--)
{
f[i][j]+=f[i-1][k];
f[i][j]%=1799999;
}
else
for(int k=0;k<=j;k++)
{
f[i][j]+=f[i-1][k];
f[i][j]%=1799999;
}
}
printf("%d",f[n][m]%1799999);
}
f[i][j]=f[i-1][j]+f[i-1][j-1]+……+f[i-1][j-i+1]
同理:f[i][j-1]=f[i-1][j-1]+f[i-1][j-2]+……+f[i-1][j-i]
两式相减得f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1],可优化,注意j、i大小。
第三题:科技节
一年一度的科技节即将到来。同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那么多活动,还要不要认真学习了?!这样不行!……于是,校长要求减少一些活动,使每位学生只能参加一项(一名同学要参加某活动,必须已报名且该活动未被去掉)。当然,他也不希望哪位同学因此不能参加任何活动。他想知道自己的方案能否实行。
去掉活动=选择活动
先将每个活动按参加人数多少排序(可能参加人数多的活动被选的几率大),搜索。每搜一排时,判断如果参加这一排的学生已经选了其他活动(之前搜过),则不选这个活动。普通搜索过60%,如果使用位运算可accept。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
long act[20];
long g[20][10];
long n,m;
bool judge;
void dfs(long p,long se[10],long num)
{
if(p==n)
{
if(num==m)judge=1;
return ;
}
long t[10],k;
for(k=0;k<10;k++)
{
if((se[k]&g[p][k])>0)break;
t[k]=se[k]|g[p][k];
}
if(k==10)dfs(p+1,t,num+act[p]);
if(!judge)dfs(p+1,se,num);
}
main()
{
freopen("scifest.in","r",stdin);
freopen("scifest.out","w",stdout);
int i,j;
while(~scanf("%ld%ld",&n,&m))
{
memset(g,0,sizeof g);
judge=0;
for(i=0;i<n;i++)
{
act[i]=0;
for(j=0;j<m;j++)
{
long x;
scanf("%ld",&x);
if(x==1)
{
act[i]++;
g[i][j/31]+=1<<(j%31);
}
}
}
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(act[i]<act[j])
{
long k=act[i];act[i]=act[j];act[j]=k;
for(k=0;k<10;k++)
{
long u=g[i][k];g[i][k]=g[j][k];g[j][k]=u;
}
}
dfs(0,g[19],0);
if(judge==1)printf("Yes\n");
else printf("No\n");
}
return 0;
}