第七集,奇思妙想
TimeLimit:2000MS MemoryLimit:128MB
64-bit integer IO format:%lld
Problem Description
在经过一个比赛的小插曲后,小A不仅得到主办方的赏识后,还捞到了一大笔钱。有了足够的钱后,他继续出发前往那个聚会城市。由于小A和小C每天都需要赶路,他们需要多买一些舒适的袜子。在离开这个城市前,他先逛了一家袜子批发商店,该商店将不同数量的袜子放入一个个盒子中,且将盒子排成一排,小A看到这样的情景,顿时好奇(程序员的本能):
若把这些箱子围成一个圈,并且拿走一段连续的箱子,且箱子中的袜子的总数量正好等于小A要买的袜子的数量M,有多少种拿法?(假设有N个盒子,盒子编号1-N)、
同在小A和小C买完了袜子之后,继续朝着聚会城市出发…
Input
有多组测试案例,
每组测试案例,第一行输入一个正整数N,M(1<=N<=10^6, 1<=M<=10^8),表示有N个箱子。
第二行输入N个非负整数Ai(1<=Ai<=100)、分别表示连续箱子里面的袜子的数量、
Output
对于每组测试案例,输出有多少种方法、
SampleInput
2 1 1 1 3 2 1 1 1 3 3 1 1 1 3 1 1 1 1 3 5 1 1 1
SampleOutput
2 3 1 3 0
【思路】:
看到这一题我的第一直觉是暴力,枚举每个点的情况,这是会有一种情况,需要考虑即 。。。。,n-1,0,。。。。就是越过起点这种情况
我就想到了,先写个判断,因为范围的最大就是一圈,如果一圈的累加得到的sum<M,那么就输出0,==的话就输出1;
如果大于再考虑接下来的情况。就是考虑跨越起点的情况,即内层循环跨越n-1到达n的时候,将n变化成0;
然后我还考虑了跑得时候,不能就是内层遍历的坐标不能大于外层坐标;就是不能重合,附上代码:
#include<stdio.h> int x[1000005]; int main() { int n,m,i,sum,flag,j,sum2; while(~scanf("%d%d",&n,&m)) { flag=0;sum2=0; for(i=0; i<n; i++) {scanf("%d",&x[i]); sum2+=x[i];} for(i=0; i<n; i++) {if(sum2<m) { break; } if(sum2==m) { flag++; break; } sum=0; j=i; sum+=x[j]; j++; if(j==n)j=0; if(sum>m)continue; if(sum==m) { flag++; continue; } while(j!=i) { sum+=x[j]; j++; if(j==n)j=0; if(sum>m)break; if(sum==m) { flag++; break; } } } printf("%d ",flag); } }
然后跑了下样例,发现正确,直接提交。。。。。
。。。。。。。超时。。。。。。。。
后来仔细一看o(n*n)的复杂度,果然凉凉,就问了下CWL学长,CWL学长说要将复杂度降为o(n)
才能过!
然后发现这题的知识点是双指针,然后发现这个是区间和
附上网站http://blog.csdn.net/linyunzju/article/details/7829073
然后更正了思路,就是两个”指针“在跑,一个在前一个在后,如果值不够,即前方指针++;如果超过,即后面指针++;
但是这题还是要魔改一下,让其可以跑过n值。
其他跟第一个思路相似;
附上代码:
#include<stdio.h> int x[1000005]; int main() { int n,m,i,l,r,Sum,sum,flag,a; while(~scanf("%d%d",&n,&m)) { Sum=0; for(i=0; i<n; i++) { scanf("%d",&x[i]); Sum+=x[i]; } l=0; r=0; a=0; flag=0; if(Sum==m)printf("1 "); if(Sum<m)printf("0 "); if(Sum>m) { sum=x[l]; while(l!=n) { if(sum<m) { r++; if(r==n) { r=0; } sum+=x[r]; } if(sum==m) { flag++; r++; if(r==n) { r=0; } sum+=x[r]; } if(sum>m) { l++; sum=sum-x[l-1]; } } printf("%d ",flag); } } return 0; }
然后一发ac。