校赛个人训练赛第五场报告
今天战绩还行,AC了5题,今天总体没有太复杂的算法题,不过测试数据强度比之前有所增加 我的钱四题很早就过了,但是第五题很晚才出主要是代码写得太混乱,思路也错了两次 我过的题有五道,分别是ABCDG
A Coming Near
A题是计算两个多边形的最近距离
由于数据量不是很大,所以O(n^2)的算法就能过,也就是枚举,每一个用例的最坏情况是310001000
具体是先枚举每两个点的距离,记录最小值
再枚举每个点到另一个多边形上每条直线的距离,记录最小值即可
不过lpld的因为越界导致的WA问题值得借鉴(及时把long型转为double型)
#include<iostream>
#include<cmath>
using namespace std;
struct vertex
{
long x,y;
};
vertex prisonA[1000],prisonB[1000];
double disBetweenAB(int posA,int posB)
{
double tmp1 = prisonA[posA].x - prisonB[posB].x;
double tmp2 = prisonA[posA].y - prisonB[posB].y;
return sqrt(tmp1 * tmp1 + tmp2 * tmp2);
}
double disBetweenPointAndLine(long x0,long y0,long x1,long y1,long x2,long y2)
{
double a = y1-y2;
double b = x2-x1;
double c = x1*y2-x2*y1;
double d = (a*x0+b*y0+c)/sqrt(a*a+b*b);
double xp = (b*b*x0-a*b*y0-a*c)/(a*a+b*b);
double yp = (-a*b*x0+a*a*y0-b*c)/(a*a+b*b);
double xb = (x1>x2)?x1:x2;
double yb = (y1>y2)?y1:y2;
double xs = x1+x2-xb;
double ys = y1+y2-yb;
if(xp > xb || xp < xs || yp > yb || yp < ys)
return 50000000;
else
return fabs(d);
}
int main()
{
int m,n;
while(scanf("%d %d",&n,&m),n || m)
{
int i,j;
for(i = 0 ; i < n ; i ++)
scanf("%ld %ld",&prisonA[i].x,&prisonA[i].y);
for(i = 0 ; i < m ; i ++)
scanf("%ld %ld",&prisonB[i].x,&prisonB[i].y);
double tmpDouble = disBetweenAB(0,0);
for(i = 0 ; i < n ; i ++)
for(j = 0 ; j < m ; j ++)
if(disBetweenAB(i,j) < tmpDouble)
tmpDouble = disBetweenAB(i,j);
for(i = 0 ; i < n ; i ++)
for(j = 0 ; j < m ; j ++)
{
double tmpDouble2 = disBetweenPointAndLine(prisonA[i].x,prisonA[i].y
,prisonB[j].x,prisonB[j].y,prisonB[(j+1)%m].x,prisonB[(j+1)%m].y);
if(tmpDouble2 < tmpDouble)
tmpDouble = tmpDouble2;
};
for(i = 0 ; i < m ; i ++)
for(j = 0 ; j < n ; j ++)
{
double tmpDouble2 = disBetweenPointAndLine(prisonB[i].x,prisonB[i].y
,prisonA[j].x,prisonA[j].y,prisonA[(j+1)%n].x,prisonA[(j+1)%n].y);
if(tmpDouble2 < tmpDouble)
tmpDouble = tmpDouble2;
};
printf("%.2lf\n",tmpDouble);
}
return 0;
}
B Love Letter
B题是要求重新排列单词,使之成为字典里的单词,以此读懂别人打乱加密的Love Letter
这题很简单,直接一个一个单词查找就行了,不过要注意一下换行的位置,因为题目要求输出和输入一样
继续贴代码:
#include<iostream>
#include<cstring>
using namespace std;
char dir[101][25];
int dirCharNum[101][26] = {0};
int lenDir[101];
char tmpChar[50];
void check(char c[],int n)
{
char cN[26] = {0};
for(int i = 0 ; i < n ; i ++)
{
int len = strlen(c);
if(len != lenDir[i] || c[0] != dir[i][0] || c[len - 1] != dir[i][lenDir[i] - 1])
continue;
memset(cN,0,sizeof(cN));
for(int j = 0 ; j < len ; j ++)
cN[c[j] - 'a'] ++;
int isMatch = 1;
for(int k = 0 ; k < len ; k ++)
if(cN[k] != dirCharNum[i][k])
{
isMatch = 0;
break;
};
if(isMatch)
{
printf("%s",dir[i]);
break;
}
}
}
int main()
{
int n;
cin>>n;
int i,j;
for(i = 0 ; i < n ; i ++)
{
scanf("%s",dir[i]);
lenDir[i] = strlen(dir[i]);
for(j = 0 ; j < lenDir[i] ; j ++)
dirCharNum[i][dir[i][j] - 'a'] ++;
}
while(scanf("%s",tmpChar) != EOF)
{
check(tmpChar,n);
if(getchar() == '\n')
printf("\n");
else
printf(" ");
}
return 0;
}
C Change Base
C题是一道进制转换题,稍微思考一下就能推出公式了,然后每次处理mod一个10007就行
(注: a % c + b % c = ( a + b ) % c ( a * b ) % c = ( a % c * b % c ) % c )
代码:
#include<iostream>
#include<cstring>
using namespace std;
char input[1002];
long TypeTo10(char c[],int m,int mod)
{
int tmpInt = 0;
int len = strlen(c);
for(int i = 0 ; i < len ; i ++)
tmpInt = (tmpInt * m + c[i] - '0') % mod;
return tmpInt;
}
int main()
{
int t,m;
cin>>t;
while(t --)
{
cin>>m>>input;
cout<<TypeTo10(input,m,10007)<<endl;
}
return 0;
}
D Equation
D题要用Hash的思想,但是因为是long型的数据而且数据量不大(1000*1000),可以不写哈希函数,直接映射
我的代码如下:
#include<iostream>
using namespace std;
long hash[2000001];
long ro[3000001] = {0};
long f2[1001];
int main()
{
int t;
long r;
for(r = 0 ; r <= 1000 ; r ++)
f2[r] = r * r;
cin>>t;
while(t --)
{
scanf("%ld",&r);
if(ro[r])
{
printf("%ld\n",ro[r]);
continue;
}
memset(hash,0,sizeof(hash));
long i,j;
for(i = 0 ; f2[i] <= r && i <= 1000 ; i ++)
for(j = 0 ; j <= i; j ++)
if(j == i)
hash[f2[i] + f2[j]] ++;
else
hash[f2[i] + f2[j]] += 2;
long tmpInt = 0;
for(i = 0 ; f2[i] <= r && i <= 1000 ; i ++)
if(r - f2[i] <= 2000000)
tmpInt += hash[r - f2[i]];
printf("%ld\n",tmpInt);
ro[r] = tmpInt;
}
return 0;
}
G Fermat square prime
G题是计算能用a^2+b^2表示的素数(a,b为素数)
我的大体思路是先筛出素数表,再把素数依次组合,算出所有能这么表示的数
最后再读入数据,判断读入的数据是否是能以a^2+b^2的素数
代码如下:
#include<iostream>
using namespace std;
#define MAXN 1000001
long prime[MAXN],numPrime = 0;
int a[MAXN] = {0};
int isFQSP[MAXN] = {0};
long f2[1000] = {0};
int main()
{
//线性筛素数复杂度O(n)这个很重要,由于数据量小,可以打表
long i,j,k;
for(i = 2 ; i < 1000 ; i ++)
{
if(!a[i])
prime[numPrime ++] = i;
for(j = 0 ; j < numPrime && prime[j] * i <MAXN ; j ++)
{
a[prime[j] * i] ++;
if(i % prime[j] == 0)
break;
}
}
for(i = 0 ; i < numPrime && prime[i] < 1000; i ++)
f2[prime[i]] = prime[i] * prime[i];
for(i = 0 ; i < numPrime && prime[i] < 1000; i ++)
for(j = 0 ; j <= i ; j ++)
if(f2[prime[i]] + f2[prime[j]] < MAXN && !a[f2[prime[i]] + f2[prime[j]]])
isFQSP[f2[prime[i]] + f2[prime[j]]] ++;
int t;
scanf("%d",&t);
while(t --)
{
scanf("%ld",&k);
if(isFQSP[k])
printf("yes\n");
else
printf("no\n");
}
return 0;
}
这次总体感觉前期不错,后期就一直卡住了,想到的算法错误浪费了我很多时间 最后一题的思路错误导致一直WA,以后需要注意,思路清晰很重要。