2019 GDUT Winter Training I (dfsbfs二分三分尺取) 题解
A题
题面:
A-尺取
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 Input
2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
Sample Output
2
3
题面描述:
这个题目的意思大概就是输入T组数据,然后对于每组数据,输入一个N和S,然后第二行输入N个数,然后这个题就是要求最少需要多少个连续的数加起来大于等于S。
题目分析:
这个题目就是很一般的尺取题,我们首先按照题目的格式把数据输入进来,然后设置三个变量,分别代表这N个数的子序列的左端点,右端点和这个子序列中所有数的和,一开始指向左端点和右端点的两个变量分别指向这N个数的第一个数,然后计算子序列总和的那个变量就等于第一个数。
接下来就是这个题目的关键步骤,如果子序列的和小于S,那么右端点不断加一,扩张这个子序列,直到这个子序列的和大于或者等于S为止,一旦这个子序列的和大于或者等于S之后,那么我们就要记录这个子序列的长度,与之前的子序列的长度进行比较,取最小值,然后就将这个子序列的左端点不断加一,直到这个子序列的和小于S,不断重复以上操作,直到记录两个端点的变量指向第N个数时结束。
最后把记录到的子序列长度的最小值输出即可。
代码:
#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstdlib>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define reg register
#define ll long long
#define ull unsigned long long
#define INF 0x3fffffff
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
using namespace std;
const int Maxn=1e5+5;
int num[Maxn];
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
int n,s,ans=INF;
scanf("%d%d",&n,&s);
for (reg int i=1;i<=n;i++) scanf("%d",&num[i]);
num[n+1]=0;
int left=1,right=1,sum=num[1];
while (left<=n && right<=n)
{
while (sum<s && right<=n) sum+=num[++right];
while (sum>=s && left<=right)
{
ans=min(ans,right-left+1);
sum-=num[left++];
}
}
if (ans<INF) printf("%d\n",ans);else printf("0\n");
}
return 0;
}
B题
题面:
B-尺取
King George has recently decided that he would like to have a new design for the royal graveyard. The graveyard must consist of several sections, each of which must be a square of graves. All sections must have different number of graves.
After a consultation with his astrologer, King George decided that the lengths of section sides must be a sequence of successive positive integer numbers. A section with side length s contains s 2 graves. George has estimated the total number of graves that will be located on the graveyard and now wants to know all possible graveyard designs satisfying the condition. You were asked to find them.
Input
Input file contains n --- the number of graves to be located in the graveyard (1 <= n <= 10^14 ).
Output
On the first line of the output file print k --- the number of possible graveyard designs. Next k lines must contain the descriptions of the graveyards. Each line must start with l --- the number of sections in the corresponding graveyard, followed by l integers --- the lengths of section sides (successive positive integer numbers). Output line's in descending order of l.
Sample Input
2030
Sample Output
2
4 21 22 23 24
3 25 26 27
题面描述:
这个题目的意思就是给你一个范围从1到1e14的正整数n,然后要求出所有连续自然数序列平方的和等于n的自然数序列,并把这些这些连续自然数序列平方的和的数量,连续自然数序列的长度以及具体的连续自然数一一按照题目格式输出出来。
题目分析:
这道题虽然是一道看似很简单的尺取题,但是不少人看到1e14这个数字会认为这道题用尺取去做会超时,但是其实并不会,因为把1e14开平方之后只有1e7而已,所以并不会超时。这道题调试起来挺麻烦的,所以挺考验我们代码的严谨性。
首先,我们先初始化三个变量,分别代表连续自然数序列的最小自然数,连续自然数序列的最大自然数和这个连续自然数序列中所有数平方的和,前两个变量初始化值为1,那么第三个变量值自然也是1。
下面就是这道题的最关键的地方,如果这个连续自然数序列中的所有数平方的和小于n,那么我们就要不断去插入比这个连续自然数序列的最大自然数大一的数,并且让记录这个序列所有数平方的和的变量加上这个新插入到这个序列的数的平方,直到这个序列所有数平方的和大于等于n,如果大于n的话,就删除这个序列的最小自然数,直到这个序列所有数平方的和小于等于n,如果等于n的话,用两个数组或者一个结构体数组记录这个序列的最小自然数和最大自然数,然后删除这个序列的最小自然数,不断重复以上操作,直到这个序列最大自然数的平方大于等于n结束。
然后输出满足要求的连续自然数序列的数量,每个连续自然数序列的自然数数量以及具体自然数。
代码:
#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstdlib>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define reg register
#define ll long long
#define ull unsigned long long
#define INF 0x3fffffff
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
using namespace std;
const int Maxn=1e6+5;
struct node
{
int left,right;
};
node rec[Maxn];
int main()
{
ll n;
int ans=0;
scanf("%lld",&n);
ll left=1,right=1,temp=1;
while (right*right<=n)
{
while (temp<n)
{
right++;
temp+=right*right;
}
while (temp>n && left<=right)
{
temp-=left*left;
left++;
}
if (temp==n)
{
rec[++ans].left=left;
rec[ans].right=right;
temp-=left*left;
left++;
}
}
printf("%d\n",ans);
for (reg int i=1;i<=ans;i++)
{
printf("%d ",rec[i].right-rec[i].left+1);
for (reg int j=rec[i].left;j<=rec[i].right;j++) printf("%d ",j);
printf("\n");
}
return 0;
}
C题
题面:
C-二分
Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000). His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?
农夫 John 建造了一座很长的畜栏,它包括NN (2 <= N <= 100,000)个隔间,这些小隔间依次编号为x1,...,xN (0 <= xi <= 1,000,000,000). 但是,John的C (2 <= C <= N)头牛们并不喜欢这种布局,而且几头牛放在一个隔间里,他们就要发生争斗。为了不让牛互相伤害。John决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢
Input
* Line 1: Two space-separated integers: N and C * Lines 2..N+1: Line i+1 contains an integer stall location, xi
第一行:空格分隔的两个整数N和C
第二行---第N+1行:i+1行指出了xi的位置
Output
* Line 1: One integer: the largest minimum distance
第一行:一个整数,最大的最小值
Sample Input
5 3 1 2 8 4 9
Sample Output
3 把牛放在1,4,8这样最小距离是3
Hint
题面描述:
这个题目意思是输入隔间的数目N,奶牛的数目C以及各个隔间的位置xi,然后题目要求的是如何在这N个隔间放置C头奶牛,使得任意两头奶牛距离的最小值最大,并且输出这个值。
题目分析:
首先这个题目直接求解是相当困难的,所有我们换位思考,如果我们知道任意两头奶牛之间的最小距离,然后判定能否放置这N头奶牛,如果可以放置的话,那么证明这个最小距离是存在的,根据贪心策略,我们先把隔间的位置从小到大进行排序,然后先从隔间位置x最小的先开始放置奶牛,然后找到距离放置上一头奶牛的隔间大于或等于最小距离的隔间放置奶牛,按照这样子的规则放置奶牛,并且计算放置奶牛的数目,如果可以放置奶牛的数目大于n,那么证明这个最小距离可以适当地增大,如果可以放置奶牛的数目小于n的话,那么证明这个最小距离应该适当地减小,最后把那些奶牛数目大于n或者小于n的距离去掉后,那么就会剩下一个奶牛数目等于n的距离区间,那么当中的最大值就是答案。
那么我们会发现,随着可以放置奶牛的数目的增大,任意两头奶牛之间的最小距离也会增大,那么很明显存在单调性,因此我们可以利用二分答案来节省时间,尽快把答案找出来。
代码:
#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstdlib>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define reg register
#define ll long long
#define ull unsigned long long
#define INF 0x3fffffff
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
using namespace std;
const int Maxn=1e5+5;
int n,num[Maxn],stalls[Maxn];
int check(int dist)
{
int previous=stalls[1],ans=1;
for (reg int i=2;i<=n;i++)
if (stalls[i]-previous>=dist)
{
previous=stalls[i];
ans++;
}
return ans;
}
int main()
{
int c;
scanf("%d%d",&n,&c);
for (reg int i=1;i<=n;i++) scanf("%d",&stalls[i]);
sort(stalls+1,stalls+n+1);
int low=0,high=stalls[n];
while (low<=high)
{
int mid=(low+high)>>1;
if (check(mid)>=c) low=mid+1;else high=mid-1;
}
printf("%d\n",high);
return 0;
}
D题
题面:
D-二分
When a thin rod of length L is heated n degrees, it expands to a new length L'=(1+n*C)*L, where C is the coefficient of heat expansion.
When a thin rod is mounted on two solid walls and then heated, it expands and takes the shape of a circular segment, the original rod being the chord of the segment.
Your task is to compute the distance by which the center of the rod is displaced.
Input
The input contains multiple lines. Each line of input contains three non-negative numbers: the initial lenth of the rod in millimeters, the temperature change in degrees and the coefficient of heat expansion of the material. Input data guarantee that no rod expands by more than one half of its orig