USACO4.3.2——质数方阵暴力解法
题面链接:这里;
读过题后,就不难发现这是一道填数题,先说填法,大多数人一开始肯定想到一行行填,一列列填,填完后整体判断——大数据直接把你T废:
于是我们就开始关注一些已经确定的点,确定的点越多,可供选择的素数就越少,运行速度就越快,请看下图:
图中的深红色(最左上角)表示题目中确定的点,我们先填第一行第一列(红色),这样有一个约束条件(一头确定),再填右上-左下的那条斜边(紫色),这样有两个约束条件(一头一尾已经确定),再填左上-右下的那条斜边(深蓝),再填浅蓝和绿色,它们都有两个约束条件。最后算出橙色的值,用总值减去其他四个数的值,如果是负数或大于10,就退回来重新做。
整体做完后,按照题目所给的条件进行判断,不符合就退回来重新做。
输出答案前需要先排序,将答案二维数组存到一个字符串中,这样就可以方便比较。
这里需要重点提的一点便是判质,下面是我刚开始写的一段代码:
bool Judge_Num(int Num) {
for (register int i = 2; i <= sqrt(Num); i++)
if (Num % i == 0)
return false;
// cout<<Num<<endl;
return true;
}
注意,它会爆——每次循环计算一次sqrt是很耗时间的,所以,我做了以下改进:
bool Judge_Num(int Num) {
int T=sqrt(Num);//这样只要计算一次sqrt
for (register int i = 2; i <= T; i++)
if (Num % i == 0)
return false;
// cout<<Num<<endl;
return true;
}
可是还是会超时(Num是一个五位数,每次循环少说也要100次),能不能将判质时间缩到O(1)呢?
可以的:
我们在填数之前先用欧拉筛将10000到99999中的素数筛出来,用bool数组Visited储存,Visited[N]=1表示N是质数,Visited[N]=0表示N是不是质数,这样,每次判质时,我们只需要:
bool Judge_Num(int Num){
return true-Visited[Num];
}
万事大吉
代码(号称USACO史上最长):
#include "bits/stdc++.h"
using namespace std;
struct Unsigned {
int Size, Num[1001];
int E[1001][11];
} Prime[11];//储存每一个素数
int Sum, Start, Used[9], Result[9][9], Size, prime[100100];
bool Can, Visited[100101];
const int N = 5, M = 9;
struct Out {
string Name;
int Num_Result[9][9];
friend bool operator<(Out Num1, Out Num2) { ret