A题 DIY Wooden Ladder
签到题,求n-2和第二大的最小值
#include<bits/stdc++.h>
using namespace std;
int arr[100020];
int main()
{int t,n;cin>>t;while(t--){cin>>n;for(int i=0;i<n;i++)cin>>arr[i];sort(arr,arr+n);cout<<min(arr[n-2]-1,n-2)<<endl;}return 0;
}
B题 Pillars
水题,求峰值,两边扫描,若不单调为NO
#include<bits/stdc++.h>
using namespace std;
int arr[200020];
int brr[200020];
int main()
{int n;cin>>n;bool flag=false;int cnt=0;int maxa=0;for(int i=0;i<n;i++){cin>>arr[i];if(maxa<arr[i]){maxa=arr[i];cnt=i;}}for(int i=0;i<cnt-1;i++)if(arr[i]>arr[i+1]){cout<<"NO"<<endl;return 0;}for(int i=cnt+1;i<n-1;i++){if(arr[i]<arr[i+1]){cout<<"NO"<<endl;return 0;}}cout<<"YES"<<endl;return 0;
}
C题 Array Splitting
差分区间,排序后删去后K-1个区间的差,求前面所有差的和
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
using namespace std;
int n,k,arr[300030];
vector<int>brr;
int main()
{cin>>n>>k;if(n==k){cout<<0<<endl;return 0;}for(int i=0;i<n;i++){cin>>arr[i];if(i!=0)brr.push_back(arr[i]-arr[i-1]);}sort(brr.begin(),brr.end());ll sum=0;for(int i=0;i<brr.size()-k+1;i++){sum+=brr[i];}cout<<sum<<endl;return 0;
}
D题 Yet Another Subarray Problem
dp题,有原公式\(\sum_{i=l}^r{a_i}-k*[(l-r+1)/m]\)得出全部用前缀和转换后的公式\(S_r-S_l-k*[(r-l)/m]\).
构造一个m大小的数组,存放每次循环一个m大小的段取得的最小值即\(S_l\),用res存放i选取的r的值的最大值,即\(res=max(res,S_i-min(f)-k*[(i-l)/m)]\)。
对于取余>=0的多减去一个k即可。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
using namespace std;
ll n,m,k,arr[300030],res=0,f[20];
int main()
{cin>>n>>m>>k;for(int i=1;i<=n;i++){cin>>arr[i];}FOR(i,0,20)f[i]=0;f[0]=-k;for(int i=1;i<=n;i++){arr[i]+=arr[i-1];//前缀和for(int j=0;j<m;j++){if(j>=i%m){//未超过一段 res=max(res,arr[i]-f[j]-k*(i/m+1));//前缀和-最小值前缀和 } else{//超过一段+1 res=max(res,arr[i]-f[j]-k*(i/m+2));}} f[i%m]=min(f[i%m],arr[i]-k*(i/m+1));//所有的m段中现存最小值 }cout<<res<<endl;return 0;
}