【USACO】ariprog

输入 : N  M

要找到长度为 N 的等差数列,要求数列中每个数字都可以表达成 a^2 + b^2 的和, 数字大小不超过M^2 + M^2

输出: 等差数列首元素 间隔 (多组答案分行输出)

解题思路:因为等差数列的数字都是平房和数  所以先生成所有的 从0 - M^2 + M^2的平方和数 去掉相同的并从小到大排序

然后对 所有间隔 、 首元素 做循环 判断能否找到以该首元素和间隔为条件的其他N-1个需要的数字 可以就存成答案;

提交后超时了.... test 5的时候 超了5s 正在想简化办法 超时的代码



#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAXN 200000
int cmp(const void *va, const void *vb)
{
return (*(int *)va) - (*(int *)vb);
}

int find(int * bisquare, int binum, int num)
{
int i;
for(i = 0; i < binum; i++)
{
if(bisquare[i] == num)
return 1;
}
return 0;
}

int main()
{
FILE *in, *out;
in = fopen("ariprog.in", "r");
out = fopen("ariprog.out", "w");

int bisquare[40000]; //存储所有可以用的平方数
int binum = 0; //存储可用平方数的个数
int ans[10000][2];
int anum = 0; //答案个数
int gap[25]; //存储间隔
int M, N;
int i, j, k;

for(i = 0; i < 40000; i++)
{
bisquare[i] = MAXN;
}

fscanf(in, "%d %d", &N, &M);

for(i = 0; i <= M; i++)
{
for(j = 0; j <= M; j++)
{
bisquare[binum] = i * i + j * j;
binum++;
}
}

qsort(bisquare, binum, sizeof(bisquare[0]), cmp);

//去掉相同的平方和数
int numt = binum;
for(i = 0; i < numt; i++)
{
if(bisquare[i] == bisquare[i + 1])
{
bisquare[i] = MAXN;
binum--;
}
}
qsort(bisquare, numt, sizeof(bisquare[0]), cmp);

int flag;
//对所有间隔大小, 所有起始位搜索
for(i = 1; i <= M * M * 2; i++)
{
for(j = 0; j < binum - N + 1; j++)
{
flag = 1;
for(k = 1; k < N; k++)
{
if(find(bisquare, binum, bisquare[j] + k * i) == 0)
{
flag = 0;
break;
}
}
if(flag == 1)
{
ans[anum][0] = bisquare[j];
ans[anum][1] = i;
anum++;
}
}
}

if(anum > 0)
{
for(i = 0; i < anum; i++)
{
fprintf(out, "%d %d\n", ans[i][0], ans[i][1]);
}
}
else
{
fprintf(out, "NONE\n");
}

return 0;

}

----------------

对于查找的办法做了化简 之前用find函数一个一个的比较 但实际上 我们只需要搜索与当前首元素右侧相邻的一些数字,
若发现搜索的数字与当前首元素的差值已经大于n个间隔了 则返回查找失败

方法:存储相邻两个数之间的差值, 从当前首元素开始对差值求和,求和值不能大于间隔

修改的部分代码:


    for(i = 0; i < binum - 1; i++)
{
gap[i] = bisquare[i + 1] - bisquare[i];
}
//..................
//if(find(bisquare, binum, bisquare[j] + k * i) == 0)
//{
// flag = 0;
// break;
//}
int inter = 0;
while(inter < i && m <= binum - 1)
{
inter = inter + gap[m];
m++;
}
if(inter != i)
{
flag = 0;
break;
}
//....................

修改后 test5 通过了 但test6 还是超时了.... 还要继续化简

----------------------

继续对查找过程优化 用目前最快的二分查找 O(logn) 的 查找范围是首元素之后的元素 真的是数量级的变快了 test5从 4s+ 变到了 0.389s
只是test 6 仍然超时了... 在自己电脑上跑了一下 差不多10s的样子会出来结果 也比之前的查找快多了  果然,学了就要用啊........
   查找的算法见下面  还需要继续优化


int BinarySearch(int * T, int left, int right, int x)
{

int l = left, r = right;
while(l < r)
{
int m = (l + r) / 2;
int aa= T[m];
if(T[m] == x)
{
return 1;
}
else if(T[m] < x)
{
l = m + 1;
}
else
{
r = m - 1;
}
}
if(T[l] == x)
{
return 1;
}
return 0;
}

---------------------------------------------------------

用了个及其NC的优化办法  把间隔循环的上限设到 3000  , 首元素循环上限设到 第10000个元素
 算是半个作弊了.... 代码主要就是在这两个地方耗时间。间隔循环是 M^2数量级个,首元素binum是(M+1)^2的量级。这两个一嵌套就是M^4
 不知道用什么规则化简, 只好强制设上限了。 AC代码


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAXN 200000
int cmp(const void *va, const void *vb)
{
return (*(int *)va) - (*(int *)vb);
}

int BinarySearch(int * T, int left, int right, int x)
{

int l = left, r = right;
while(l < r)
{
int m = (l + r) / 2;
int aa= T[m];
if(T[m] == x)
{
return 1;
}
else if(T[m] < x)
{
l = m + 1;
}
else
{
r = m - 1;
}
}
if(T[l] == x)
{
return 1;
}
return 0;
}

int main()
{
FILE *in, *out;
in = fopen("ariprog.in", "r");
out = fopen("ariprog.out", "w");

int bisquare[70000]; //存储所有可以用的平方数
int binum = 0; //存储可用平方数的个数
int ans[10000][2];
int anum = 0; //答案个数
int M, N;
int i, j, k;

for(i = 0; i < 40000; i++)
{
bisquare[i] = MAXN;
}

fscanf(in, "%d %d", &N, &M);

for(i = 0; i <= M; i++)
{
for(j = 0; j <= M; j++)
{
bisquare[binum] = i * i + j * j;
binum++;
}
}

qsort(bisquare, binum, sizeof(bisquare[0]), cmp);

//去掉相同的平方和数
int numt = binum;
for(i = 0; i < numt; i++)
{
if(bisquare[i] == bisquare[i + 1])
{
bisquare[i] = MAXN;
binum--;
}
}
qsort(bisquare, numt, sizeof(bisquare[0]), cmp);

int flag;
//对所有间隔大小, 所有起始位搜索
for(i = 1; i <= /*M * M * 2*/3000; i++)
{
for(j = 0; j < 10000 && j < binum - N + 1; j++)
{
flag = 1;
int m = j;
for(k = 1; k < N; k++)
{
if(BinarySearch(bisquare, j + 1, binum - 1, bisquare[j] + k * i) == 0)
{
flag = 0;
break;
}

}
if(flag == 1)
{
ans[anum][0] = bisquare[j];
ans[anum][1] = i;
anum++;
}
}
}

if(anum > 0)
{
for(i = 0; i < anum; i++)
{
fprintf(out, "%d %d\n", ans[i][0], ans[i][1]);
}
}
else
{
fprintf(out, "NONE\n");
}
return 0;
}

----------------------------------

看了答案  用了一种更NB的查找方法  直接建一个0,1大数组 有该数设为1 没有设为0 直接读取即可 改为这种常数时间的查找后
时间又是呈数量级式的下降了

间隔的上限为 M * M * 2 / (N - 1)   首元素的循环条件为 bisquare[j] + (N - 1) * 当前间隔
<= M * M * 2 整体修改后 计算时间均在2s以内

最终版完整代码:


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAXN 200000
int cmp(const void *va, const void *vb)
{
return (*(int *)va) - (*(int *)vb);
}

int BinarySearch(int * T, int left, int right, int x)
{

int l = left, r = right;
while(l < r)
{
int m = (l + r) / 2;
int aa= T[m];
if(T[m] == x)
{
return 1;
}
else if(T[m] < x)
{
l = m + 1;
}
else
{
r = m - 1;
}
}
if(T[l] == x)
{
return 1;
}
return 0;
}

int main()
{

FILE *in, *out;
in = fopen("ariprog.in", "r");
out = fopen("ariprog.out", "w");

int bisquare[70000]; //存储所有可以用的平方数
int binum = 0; //存储可用平方数的个数
int ans[10000][2];
int is[125001] = {0};
int anum = 0; //答案个数
int M, N;
int i, j, k;

for(i = 0; i < 70000; i++)
{
bisquare[i] = MAXN;
}

fscanf(in, "%d %d", &N, &M);

for(i = 0; i <= M; i++)
{
for(j = 0; j <= M; j++)
{
if(is[i * i + j * j] == 0) //用is判断可以去掉重复的数字
{
bisquare[binum] = i * i + j * j;
binum++;
is[i * i + j * j] = 1;
}
}
}

qsort(bisquare, binum, sizeof(bisquare[0]), cmp);

int flag;
int upperb = M * M * 2 / (N - 1);
//对所有间隔大小, 所有起始位搜索
for(i = 1; i <= upperb; i++)
{
for(j = 0; bisquare[j] + (N - 1) * i <= M * M * 2; j++)
{
flag = 1;
int m = j;
for(k = 1; k < N; k++)
{
if(is[bisquare[j] + k * i] == 0)
{
flag = 0;
break;
}

}
if(flag == 1)
{
ans[anum][0] = bisquare[j];
ans[anum][1] = i;
anum++;
}
}
}

if(anum > 0)
{
for(i = 0; i < anum; i++)
{
fprintf(out, "%d %d\n", ans[i][0], ans[i][1]);
}
}
else
{
fprintf(out, "NONE\n");
}
return 0;
}

【USACO】ariprog

时间: 2024-11-07 17:38:10

【USACO】ariprog的相关文章

【USACO】checker

一看题目 经典的8皇后问题 不过是皇后数量可变而已 不用想 回溯法. 需要个生成每次可选择序列的函数, 在存储可选择的序列时按照先大后小的顺序排的.这样每次找最小和去掉最小都很方便,只要有个记录数量的变量 每次减1就好了.  写完后,居然悲剧了. 在皇后数量达到13时, 在自己电脑上跑 内存溢出了 在评分系统上超时了.需要优化. #include <stdio.h> //k计算第几层从0开始 x已经摆好的位置 S存放产生的位置 l存放产生的数量 N一共有多少位置可以选择 int calcula

【USACO】milk3

倒牛奶的问题, 开始看感觉跟倒水的问题很像, 想直接找规律, 写个类似于循环取余的代码. 但后来发现不行,因为这道题有三个桶,水量也是有限制的.只好用模拟的方法把所有的情况都试一遍. 建一个state[21][21][21]的数组存储出现过的状态.对于遍历状态,对每一种状态, 分别采用六种处理方法,若有新状态出现这将新状态置为1,同时标记flag++:若所有循环之后,flag == 0, 就说明遍历完成了. 开始脑子抽筋了, 写了个多出口的程序, 显然是错的.如下: int mothersmil

【USACO】calfflac

关键:以回文中心位置为变量进行遍历 //必须把纯字母先提出来 否则肯能会出现错误 比如: lvlv= 在检查长度4时 lvlv认为不是回文 vlv=认为是回文 但实际上 lvl 出现的要更早一些 //判断回文的方法 可以输入字符串后 左右比较 或者分别正序 逆序 存储 判断是否相等 //我的思路不对 严重超时了 我是以长度为变量进行循环 对于每个长度 每一个不同起始点的序列都需要对 整个序列重新判断一次是否为回文 O(n^3) //答案中 以中心字母为变量进行循环 只需要对每一个字母做为中心变量

【USACO】第一章总结

做了大半个月,终于把第一章做完了 有的题遇到了不小的坎儿,看着网上一群高中生都做得那么好,心理还是有些小郁闷的.不禁感慨我过去的四年真是虚度啊.总结一下第一章学习到的知识吧. ①闰年判断 int isleapyear(int N) { if((N%100 != 0 && N%4 ==0) || (N%400 == 0)) return 1; else return 0; } 计算闰年日期时可以用两个数组存放每个月的时间 int Year[12] = {31, 28, 31, 30, 31,

【USACO】Transformations

A square pattern of size N x N (1 <= N <= 10) black and white square tiles is transformed into another square pattern. Write a program that will recognize the minimum transformation that has been applied to the original pattern given the following l

【USACO】奶牛跑步2

P1443 - [USACO]奶牛跑步2 Description FJ的N(1 <= N <= 100,000)头奶牛们又兴高采烈地出来运动了!她们在一条无限长的小路上跑步,每头牛起跑的位置都不同,速度也不尽相同. 道路中划出了若干条跑道,以便她们能快速"超车",同一跑道中的任意两头牛都不会出现在相同的位置.不过FJ不愿让任何一头牛更换跑道或者调整速度,他想 知道如果让牛们跑足T(1 <= T <= 1,000,000,000)分钟的话,至少需要多少条跑道才能满

【USACO】beads

题目: You have a necklace of N red, white, or blue beads (3<=N<=350) some of which are red, others blue, and others white, arranged at random. Here are two examples for n=29: 1 2 1 2 r b b r b r r b r b b b r r b r r r w r b r w w b b r r b b b b b b

【USACO】Mother&#39;s Milk(搜索)

一开始还在想去重的问题,结果发现后台数据貌似没有重复的情况= = /* ID: 18906421 LANG: C++ PROG: milk3 */ #include<cmath> #include<cstdio> #include<vector> #include<algorithm> using namespace std; const int maxn = 25; int vis[maxn][maxn][maxn] = {0}; vector<in

【USACO】草地排水

Drainage Ditches 草地排水 usaco 4.2.1描述在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪).作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量.农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小