这是16级同学第一周寒假作业的题解,内容大概是二分,双指针和预处理优化,题解不会很详细,大家要自己先去看题才行,给出题目连接:连接在这里
A.考察一下大家具体的二分水平,大于等于,大于,小于等一系列应用,用STL的二分可以很轻松解决:
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,q,a[100005],c,x,y;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d",&a[i]);
scanf("%d",&q);
for(int i = 0;i < q;i++){
scanf("%d",&c);
if(c == 0){
scanf("%d",&x);
if(x < a[1]||x > a[n]||a[lower_bound(a+1,a+1+n,x)-a]!=x) puts("-1");
else printf("%d\n",upper_bound(a+1,a+1+n,x)-a-2);
}
else if(c == 1){
scanf("%d",&x);
if(x < a[1]||x > a[n]||a[lower_bound(a+1,a+1+n,x)-a]!=x) puts("-1");
else printf("%d\n",upper_bound(a+1,a+1+n,x-1)-a-1);
}
else if(c == 2){
scanf("%d%d",&x,&y);
printf("%d\n",upper_bound(a+1,a+1+n,y)-a-(upper_bound(a+1,a+1+n,x-1)-a));
}
else if(c == 3){
scanf("%d",&x);
if(x >= a[n]) puts("-1");
else printf("%d\n",a[lower_bound(a+1,a+1+n,x+1)-a]);
}
else{
scanf("%d",&x);
if(x <= a[1]) puts("-1");
else printf("%d\n",a[lower_bound(a+1,a+1+n,x)-a-1]);
}
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
ll sum[maxn];
struct Node
{
double x,y;
}a[maxn];
bool operator <(Node a,Node b)
{
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
for (int i=0;i<n;i++)
scanf("%lf%lf",&a[i].x,&a[i].y);
for (int i = 0;i < n;i++)
sum[i] = n-1-i;
sort(a,a+n);
for(int i = 0;i < m;i++)
{
Node lll,rrr;
scanf("%lf%lf%lf%lf",&rrr.x,&rrr.y,&lll.x,&lll.y);
ll llll = lower_bound(a,a+n,lll)-a;
ll rrrr = upper_bound(a,a+n,rrr)-a-1;
printf("%I64d\n",(sum[llll] + sum[rrrr])*(rrrr-llll+1)/2);
}
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define N 10010
#define MAX 10000000
int a[N];
int main()
{
int n,m;
double len;
while(scanf("%d%d",&n,&m)!=EOF)
{
int Max = 0;
for(int i=0; i<n; i++)
{
scanf("%lf",&len);
a[i] = len * 100;
Max = max(Max , a[i]);
}
int low = 1 , high = Max;
int res = 0;
while(low <= high)
{
int mid = (low + high) >> 1;
int count = 0;
for(int i=0; i<n; i++)
count += a[i] / mid;
if(count >= m)
res = max(res , mid) , low = mid + 1;
else
high = mid - 1;
}
printf("%.2f\n",(double)res / 100.0);
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main(){
double l,va,vc,k,a[100100];
int q;
while(~scanf("%lf%lf%lf",&l,&va,&vc)){
a[0] = 0;
for(int i = 1;i <= 10000;i++)
a[i] = a[i-1]+i-1+(l/(va+vc)-1e-6);
scanf("%d",&q);
while(q--){
scanf("%lf",&k);
printf("%d\n",upper_bound(a,a+10001,k)-a-1);
}
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int n,m,a[maxn];
int main(){
while(~scanf("%d%d",&n,&m)){
int ans,sum,bot;
ans = sum = bot = 0;
for(int i = 0;i < n;i++){
scanf("%d",&a[i]);
sum += a[i];
while(sum > m) sum-=a[bot++];
if(sum == m) ans++;
}
if(bot)
for(int i = 0;i < n-1;i++){
sum += a[i];
while(sum > m) sum -= a[bot++];
if(bot >= n) break;
if(sum == m) ans++;
}
printf("%d\n",ans);
}
return 0;
}
F.求最小长度的序列和大与等于S的长度,仍然是双指针扫描,具体的看代码吧
#include <stdio.h>
#define MAX 100100
int main()
{
int T,N,S;
int i=0,data[100100],min,head=0,rear=0,sum=0;
scanf("%d",&T);
while(T--)
{
min=MAX;
scanf("%d%d",&N,&S);
for(i=0;i<N;++i)
{
scanf("%d",&data[i]);
}
head=0;
rear=1;
sum=data[0];
while(rear < N)
{
while(rear < N&&sum < S)
{
sum+=data[rear++];
}
sum-=data[head++];
while(sum>=S)
{
sum-=data[head++];
}
if (sum+data[head-1]>=S && rear-head+1<min)
{
min=rear-head+1;
}
}
if(MAX == min)
{
puts("0");
}
else
{
printf("%d\n",min);
}
}
}
G.因为n的数据够小,预处理一下前缀和,n^2也是可以卡过这道题目的:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll a[10005],sum[10005],m;
int n,q,t;
scanf("%d",&t);
while(t--){
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
scanf("%d%d",&n,&q);
for(int i = 1;i <= n;i++)
scanf("%lld",&a[i]),sum[i] = sum[i-1]+a[i];
while(q--){
int cot = 0;
scanf("%lld",&m);
for(int i = 0;i < n;i++){
for(int j = i+1;j <= n;j++){
if(sum[j] - sum[i] == m)
cot++;
}
}
printf("%d\n",cot);
}
}
return 0;
}
H.注意一下,这里的数全部都是正整数,所以双指针扫描一下,如果出现等于的数,加一下,扩大右端点,如果大于需要的数,缩进左端点即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[10006];
int main(){
int n,q,i,bot,ans,t;
ll sum,m;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&q);
for(i = 0;i < n;i++) scanf("%lld",&a[i]);
while(q--){
scanf("%lld",&m);
for(sum = bot = i = ans = 0;i < n;i++){
sum += a[i];
while(sum > m) sum -= a[bot++];
if(sum == m) ans++;
}
printf("%d\n",ans);
}
}
return 0;
}
I.因为需要查询的数在-1e6到1e6的区间里,所以可以开一个数组保存我们需要的数有多少个,可以把要查询的数加上一个1e6使得查询的数为非负数,为开数组做处理,查询的时候也加一个1e6即可,防止数组越界,判断那一段连续区间和的数是否在我们想要的区间里,不在就不管,因为题目的数据保证不会出现超过1e6或者小于-1e6的数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6;
int t,n,q,Q,c;
int a[maxn],sum[maxn],ans[2000005];
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&q);
memset(sum,0,sizeof(sum));
sum[0] = 0;
for(int i = 0;i < n;i++){
scanf("%d",&a[i]);
sum[i+1] = sum[i] + a[i];
}
memset(ans,0,sizeof(ans));
for(int i = 0;i < n;i++){
for(int j = i;j < n;j++){
c = sum[j+1]-sum[i]+maxn;
if(c >= 0&&c <= 2*maxn)
ans[c]++;
}
}
for(int i = 0;i < q;i++){
scanf("%d",&Q);
printf("%d\n",ans[Q+maxn]);
}
}
return 0;
}
J.认真看过这周算法讲堂的同学一定会做这道题目(点我去看视频啦),双指针的最好范例,具体解法自己去看视频
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
int t,n,m,l,r,w,s,x,y;
int a[maxn],sum[maxn];
int main(){
scanf("%d",&t);
while(t--){
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
scanf("%d%d%d%d",&n,&m,&s,&w);
while(m--){
scanf("%d%d",&x,&y);
a[x]++;a[y+1]--;
}
for(int i = 1;i <= n;i++)
a[i] = a[i-1] + a[i];
for(int i = 1;i <= n;i++)
sum[i] = sum[i-1] + a[i];
ll ans = 0,l = 1,r = 1;
for(int i = 1;i <= n;i++){
while(r < i&&sum[i] - sum[r] >= w)
++r;
while(l < r-1&&sum[i] - sum[l] >= s&&
sum[r-1]-sum[l] >= w)
++l;
if(l < r&&sum[i]-sum[l-1] >= s&&sum[i]-
sum[r-1] >= w&&sum[r-1]-sum[l-1]>=w)
ans += l;
}
printf("%I64d\n",ans);
}
return 0;
}
题目真多,写题解写的累死了,大家加油啊,另外加了个寒假训练的记分机制,跟寒假回来的分队是会挂钩的,具体情况点这里,看最下面写的ps:怒点这里