一年多之后再次打开usaco,发现新增了三题,于是就做了下。毕竟是getting started,难度也就很低了。
Problem1:Combination Lock
题意大致是说FJ和他的Lock Maker都拥有对Lock的控制权,FJ拥有一组三元数,LM同样如此。三元数(eg:(2,3,4))每个数字都在1-N这个范围内,只要给出的三元数中每个数字与FJ或LM的三元数距离均不超过2即可打开这把锁,1与N距离可视为1,也就是说这N个数是循环排列的。现在给出FL与LM的三元数,求有多少组三元数能够成为开锁的密钥。
题目读完,显然当N不超过5时,所有的三元数组均符合题意,答案即为N^3。当N超过5时,倘若与FJ或LM配对的任意三元数组均不发生重合,那么结果即为250。如此,只需统计发生重叠的三元数组即可,我们将FJ与LM各位上的数字进行比较,可以发现当距离为i(i<=5)时,重复的数字将会有(5-i)个,最后相乘即可。
代码如下:
#include<stdio.h>
int main()
{
FILE *fp1,*fp2;
fp1=fopen("combo.in","r");
fp2=fopen("combo.out","w");
int n,s[3],t[3],i;
int w=1,v,flag=0;
fscanf(fp1,"%d",&n);
for(i=0;i<3;i++)
fscanf(fp1,"%d",&s[i]);
for(i=0;i<3;i++)
fscanf(fp1,"%d",&t[i]);
if(n>5)
{
for(i=0;i<3;i++)
{
if(s[i]==t[i])v=0;
else if(s[i]<t[i])v=(t[i]-s[i])<(s[i]+n-t[i])?(t[i]-s[i]):(s[i]+n-t[i]);
else v=(t[i]+n-s[i])<(s[i]-t[i])?(t[i]+n-s[i]):(s[i]-t[i]);
if(v<5){w*=5-v;flag=1;}
}
if(flag)
fprintf(fp2,"%d\n",250-w);
else
fprintf(fp2,"250\n");
}
else
fprintf(fp2,"%d\n",n*n*n);
fclose(fp1);
fclose(fp2);
return 0;
}
Problem2:Wormholes
乍一看还以为是哪个最短路径的虫洞,当然其实不是。大意是说现在有N个虫洞(N为偶数),问有多少种两两配对方案使得奶牛可能被困住。奶牛始终朝着+x方向行走,从一个虫洞进去,就会从另外一个相应的虫洞出来。跟植物大战僵尸里的某个小游戏有点像哈!
由于N不超过12,我们先用深搜枚举出所有的可能配对方案,再对各个方案进行检验即可。检验时从每个虫洞都进去一遍试试看是否会发生循环就知道奶牛有没有可能被困住了。
但是注意从虫洞进去合出来是两个不一样的状态,所以标记的时候需要注意一下。
代码如下:
#include<stdio.h>
int x[12],y[12],match[12],n,ans=0,d[12],p_in[12],p_out[12];
int check_1(int s)
{
if(p_in[s])return 1;
p_in[s]=1;
if(p_out[match[s]])return 1;
p_out[match[s]]=1;
int i,min=1000000001,t=100;
for(i=0;i<n;i++)
if(x[i]==x[match[s]]&&y[i]>y[match[s]]&&y[i]<min)
{min=y[i];t=i;}
if(t<100)return check_1(t);
return 0;
}
int check()
{
int i,j;
for(i=0;i<n;i++)
{for(j=0;j<n;j++){p_in[j]=0;p_out[j]=0;}if(check_1(i)){printf("%d\n",i);return 1;}}
return 0;
}
void dfs(int r,int w)
{
int i,j;
if(w==n-2)
{
for(i=0;i<n;i++)
if(!d[i]&&i!=r){match[r]=i;match[i]=r;}
/*
int i;
for(i=0;i<n;i++)printf("%d %d\n",i,match[i]);
printf("\n");
*/
if(check())ans++;
return;
}
for(i=r+1;i<n;i++)
if(!d[i])
{
match[r]=i;
match[i]=r;
d[i]=1;
d[r]=1;
for(j=r+1;j<n;j++)
if(!d[j])
{dfs(j,w+2);break;}
d[i]=0;d[r]=0;
}
return ;
}
int main()
{
FILE *fp1,*fp2;
fp1=fopen("wormhole.in","r");
fp2=fopen("wormhole.out","w");
int i,j;
fscanf(fp1,"%d",&n);
for(i=0;i<n;i++)
fscanf(fp1,"%d%d",&y[i],&x[i]);
dfs(0,0);
fprintf(fp2,"%d\n",ans);
fclose(fp1);
fclose(fp2);
// system("pause");
return 0;
}
Problem3:Ski Course Design
大意是给出几个高度,求最小代价使得改造后的高度极差不超过17。
考虑到高度在1-100范围内,于是只需枚举所有的最小值与最大值即可(1-18,2-19…),最后求出最小代价。
代码如下:
#include<stdio.h>
int n,h[1000],p[1000];
void sort(int l,int r)
{
int ch=h[(l+r)>>1],i=l,j=r,temp;
while(i<=j)
{
while(h[i]<ch)i++;
while(h[j]>ch)j--;
if(i<=j)
{
temp=h[i];
h[i]=h[j];
h[j]=temp;
i++;j--;
}
}
if(l<j)sort(l,j);
if(i<r)sort(i,r);
return ;
}
int main()
{
FILE *fp1,*fp2;
fp1=fopen("skidesign.in","r");
fp2=fopen("skidesign.out","w");
int i,j;
fscanf(fp1,"%d",&n);
for(i=0;i<n;i++)
fscanf(fp1,"%d",&h[i]);
sort(0,n-1);
if(h[n-1]-h[0]<=17){fprintf(fp2,"0\n");return 0;}
int min=2147483647,m,l,r,s,w;
s=(h[n-1]-h[0]-17)>>1+h[0];
for(l=s;l>=1;l--)
{
r=l+17;
m=(h[0]-l)*(h[0]-l)+(h[n-1]-r)*(h[n-1]-r);
if(m>=min)break;
for(i=1;i<n-1;i++)
{
if(h[i]<l)m+=(l-h[i])*(l-h[i]);
if(h[i]>r)m+=(r-h[i])*(r-h[i]);
}
if(m<min)min=m;
}
for(l=s+1;l<=100;l++)
{
r=l+17;
m=(h[0]-l)*(h[0]-l)+(h[n-1]-r)*(h[n-1]-r);
if(m>=min)break;
for(i=1;i<n-1;i++)
{
if(h[i]<l)m+=(l-h[i])*(l-h[i]);
if(h[i]>r)m+=(r-h[i])*(r-h[i]);
}
if(m<min)min=m;
}
fprintf(fp2,"%d\n",min);
fclose(fp1);
fclose(fp2);
return 0;
}