2024_7_15~暑期40天算法集训_个人笔记(第三周)_未完成版

A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.

Input

The first line is the number of test cases. For each test case the program has to read the numbers N and S, separated by an interval, from the first line. The numbers of the sequence are given in the second line of the test case, separated by intervals. The input will finish with the end of file.

Output

For each the case the program has to print the result on separate line of the output file.if no answer, print 0.

Sample

InputcopyOutputcopy
2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
2
3

Sponsor

给出了C-子正整数S (S < 100 000 000)。
编写一个程序,求由N个小于等于10000的正整数(10 < N < 100000)组成的a序列的最小长度,以及该序列中连续元素的子序列,其和大于等于s个输入,以间隔分隔,从第一行开始。
序列的编号在第二行给出,第一行是测试用例的数量。
对于每个测试用例,程序必须读取由间隔分隔的数字N和测试用例的行。
输入将以文件的结尾结束。
对于每种情况,程序都必须在输出文件的单独行上打印结果。
如果没有答案,打印0。

题目分析:一组数据,寻找连续区间,区间里的数据和大于等于s,这个区间长度的最小值就是答案.

思路:用一个数组记录前n项和,这样区间里的值可以用前r项的和减去前l项的和来表示,初始,l=r=1(数组从1开始存),r<=n时进入循环,即遍历整个区间,进行判断,如果前r项的和减去前l-1项的和>=s,符合要求,记录区间长度判断是否最小,左指针l++,否则右指针r++,通过不断更新l和r的值框定区间范围,判断是否符合题意;

代码:

const  int maxn = 1e6 + 10;
int num[maxn];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	int n;
	cin >> n;
	while (n--)
	{
		int n1, m,minn=1000000+10;
		cin >> n1 >> m;
		for (int i = 1; i <= n1; i++)//从1开始存前n项的和
		{
			int x;
			cin >> x;
			num[i] = x + num[i - 1];
		}
		int l = 1, r = 1;
		while (r <= n1)
		{
			if (num[r] - num[l - 1] >= m)//在此中间满足题意
			{
				minn = minn < r - l+1 ? minn : r - l+1;
				//移动左指针
				l++;
			}
			else//小于m
			{
				r++;
			}
		}
		if (minn == 1000000 + 10)
		{
			cout << '0'<<"\n";
		}
		else
		{
			cout << minn<<"\n";
		}
		memset(num, 0, sizeof(num));
	}
	return 0;
};

---------------------------------------------------------------------------------------------------------------------------------错误总结:

1.排标号为1的数组,从a+1,到a+n+1

sort(a+1, a + n+1, com);//从大到小排,从1开始排,排到n+1

2,double类型sum=num*num/i,很可能爆炸,可以先/i,再算平方num/i*num;

F - 连续自然数和

Description

对一个给定的正整数 MM,求出所有的连续的正整数段(每一段至少有两个数),这些连续的自然数段中的全部数之和为 MM。

例子:1998+1999+2000+2001+2002=100001998+1999+2000+2001+2002=10000,所以从 19981998 到 20022002 的一个自然数段为 M=10000M=10000 的一个解。

Input

包含一个整数的单独一行给出 MM 的值(10≤M≤2,000,00010≤M≤2,000,000)。

Output

每行两个正整数,给出一个满足条件的连续正整数段中的第一个数和最后一个数,两数之间用一个空格隔开,所有输出行的第一个按从小到大的升序排列,对于给定的输入数据,保证至少有一个解。

Sample 1

InputcopyOutputcopy
10000
18 142 
297 328 
388 412 
1998 2002 

思路:根据M构造M的前缀和数组,用双指针l,r作为动态窗口.

代码要点,while()循环截至条件是右指针小于M,

代码:

ll a[maxn];
ll num[maxn];
int main()
{
	ios::sync_with_stdio(false);cin.tie(NULL); cout.tie(NULL);
	ll w,M;
	cin >> M;
	int flag = 1;
	for (int i = 1; i <= M; i++)
	{
		num[i] = num[i - 1] + flag;
		flag++;
	}
	int l=1 , r = 1;
	while(r<M)
	{
		if (num[r] - num[l] == M)
		{
			//输出
			cout << l+1 <<" "<< r<<"\n";
			l++;
			continue;
		}
		else if (num[r] - num[l] > M)
		{
			l++;
		}
		else
		{
			r++;
		}

	}
	return 0;
};

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

二分算法

模板:

while (r - l >= 0.001)//实数,r和l是二分枚举值,二分之后l和r的差小于0.001
{
	double m = (l + r) / 2;
	if (check())//实数二分,l和r无限逼近答案,有没有等于号不重要
	{
		l = m;
	}
	else
	{
		r = m;
	}
}

立方根

Description

给定正整数 nn,求 n33n​。答案向下取整。

Input

仅一行,一个正整数 nn。

Output

仅一行,一个正整数,表示 n33n​。向下取整输出。

Sample 1

InputcopyOutputcopy
27
3

Sample 2

InputcopyOutputcopy
100000
46

Sample 3

InputcopyOutputcopy
1000000000000000
100000

Hint

对于 100%100% 的数据,有 n≤1015n≤1015。

Sponsor

思路:整数二分枚举答案.

注意:整数二分while(l<r),当l等于r的时候跳出,

更新l的时候l=mid+1;这样最后才能跳出

结果要求向下取整.

代码:

int main()
{
	ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
	ll k, n, T;
	cin >> n;//n=27
	ll l = -100000, r = 100000;//很大的范围进行二分查找
	while (l < r)
	{
		ll mid = (l + r) / 2;
		if (mid * mid * mid < n)//有没有等于不重要
		{
			l = mid + 1;
		}
		else//大于
		{
			r = mid;
		}
	}
	//出来的时候r==l
	if (r * r * r == n) cout << r;
	else cout << r - 1;
	return 0;
};

二分刷题经验:尽量考虑边界,有些时候=加不加都一样.二分边界有可能出现问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值