风扇 blower
【问题描述】
有一个巨型风扇,它有好多好多扇片,仔细数一下,发现共有10125个。但是其中有一些扇片是坏掉的,需要将其拆下来。但是拆下来之后发现这个风扇不平衡了,所以还要拆掉一些扇片,使得最后的重心在中心的转轴上。请问最少需要拆掉多少个。
【输入文件】
输入文件blower.in的第一行包含一个正整数N,表示有N个刀片已经坏掉了。
接下来N行,每行一个整数,为坏掉的那些扇片的编号,扇片编号按顺时针方向从0开始编号。
【输出文件】
输出文件blower.out的第一行包含一个整数,为最少需要拆掉的扇片个数。
【输入样例】
4
01351 3375 3376
【输出样例】
4
【样例说明】
拆掉5401,6750,7426,9451这四个扇片。
【数据规模和约定】
对于40%的数据:N≤20。
对于100%的数据:1≤N≤10125。
这是ural1765简化的题目,1765是输入数据给定n,这一题是题目给出n,但是原题有一句很重要的话:N 最多含有两个不同的质因数
我们先回到这一题,题目给出N=10125,我们把他分解质因数,10125 = 3 × 3 × 3 × 3 × 5 × 5 × 5
就只有 3 和 5 ,那么我们就可以把圆三等分或五等分(其他的都可以有这两个得来),
【上面这个图严格说不对,只是表示一下意思,把下面看完就应该知道正确的图该怎么画了】
那么只要在任意正三角形或正五边形上有被拆掉的扇叶,那么剩下的也要被拆掉才能保持平衡
然后我们只需要枚举前面0~675 (10125 / 3 / 5 = 675)个点就行了(避免后面的重复枚举)
每次判断三角形和五边行哪个更优
这一题的标解是网络流,但是FinalSix神牛找出了如此牛逼的数学方法为何不用呢?
原题是输入数据给出N,那么我们就只需要把N进行因式分解就可以了
至于网络流的做法还真不会。。。。
测评情况(Shell)
考试:
考后:
C++ AC Code
/*http://blog.csdn.net/jiangzh7
By Jiangzh*/
#include<cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
int n;
int f[675+10][15+10];//f[i][j]表示第i个正十五边形的第j个点
void read()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int a; scanf("%d",&a);
int x=a/675;
int y=a%675;
f[y][x]=1;
}
}
int calc(int x)
{
int res=0;//枚举正三角形的情况
for(int a=0;a<5;a++)
{
int b=a+5,c=b+5;
if(!f[x][a] && !f[x][b] && !f[x][c]) continue;//没有一个点拆掉就不用拆
res+=3-f[x][a]-f[x][b]-f[x][c];//上面的点需要都被拆掉才能保持平衡
}
int res2=0;//枚举正五边形的情况,下面同理
for(int a=0;a<3;a++)
{
int b=a+3,c=b+3,d=c+3,e=d+3;
if(!f[x][a] && !f[x][b] && !f[x][c] && !f[x][d] && !f[x][e]) continue;
res2+=5-f[x][a]-f[x][b]-f[x][c]-f[x][d]-f[x][e];
}
return min(res,res2);
}
void work()
{
int res=0;
for(int i=0;i<675;i++)
res+=calc(i);
printf("%d\n",res);
}
int main()
{
freopen("blower.in","r",stdin);
freopen("blower.out","w",stdout);
read();
work();
return 0;
}