一:Educational Codeforces Round 63 (Rated for Div. 2)
C:Alarm Clocks Everywhere
题意:给出n个起始时间x和m个可以选择的事件间隔p,确定一个起始时间和时间间隔使n个起始时间都能被包含进去。
解题思路:找出n个起始时间的相邻时间间隔的最小公约数t,看是否存在p满足p=t,或者p是t的因子,输出p的位置和可选择的起始时间即可。
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int ma=3e5+10;
int n,m,k;
ll a[ma],t,c[ma];
struct node{
ll x,v;
}b[ma];
bool cmp(node e,node f){
return e.v<f.v;
}
ll gcd(ll x,ll y){
if(y==0)return x;
if(x%y==0)return y;
else return gcd(y,x%y);
}
ll read() {
ll y=0,flag=1;
char ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') y=y*10+ch-'0',ch=getchar();
return y*flag;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)c[i]=a[i]-a[i-1];
t=gcd(c[2],c[3]);
for(int i=4;i<=n;i++){//计算每个时间段的最小公约数
t=gcd(c[i],t);
}
for(int i=0;i<m;i++){//其实不用结构体排序,这是最开始的思路
b[i].v=read();
b[i].x=i+1;
}
sort(b,b+m,cmp);
for(int i=0;i<m;i++){
if(t%b[i].v==0){//找到满足的p
cout<<"YES"<<endl;
if(b[i].v!=a[1]&&b[i].v<a[1])cout<<a[1]-b[i].v<<" "<<b[i].x<<endl;//确定起始时间
else cout<<a[1]<<" "<<b[i].x<<endl;
return 0;
}
}
cout<<"NO";
return 0;
}
D: Beautiful Array
题意:给你一个长度为n的序列,找出一个区间使它区间和最大,或者使该区间乘以k之后的和最大,问最大值是多少。
解题思路:可以用动归的思路:dp[0][i]维护到第i个数不乘k所得到的最大字段和,dp[1][i]维护的是到第i个数以开始使用乘上k的最大子段和,dp[2][i]维护的是到第i个数已经结束乘以k的最大字段和。每次取max即可。
代码如下:
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int ma=3e5+10;
ll n,k,ans;
ll dp[3][ma],x;
ll read() {
ll y=0,flag=1;
char ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') y=y*10+ch-'0',ch=getchar();
return y*flag;
}
int main(){
n=read(),k=read();
for(int i=1;i<=n;i++){
x=read();
dp[0][i]=max(dp[0][i-1]+x,(ll)0);
dp[1][i]=max(dp[1][i-1]+x*k,dp[0][i]);
dp[2][i]=max(dp[2][i-1]+x,dp[1][i]);
ans=max(ans,dp[2][i]);
}
/*
O(1)内存写法;
int t1=0,t2=0,t3=0;
for(int i=0;i<n;++i){
scanf("%lld",&x);
t1=max(t1+x,(ll)0);
t2=max(t2+x*k,t1);
t3=max(t2,t3+x);
ans=max(ans,t3);
}
*/
cout<<ans;
return 0;
}
二:Educational Codeforces Round 69 (Rated for Div. 2)
C: Array Splitting
题意:给出一段递增序列,分成k个连续区间使每一个区间最大值减去最小值的和最小,问最小为多少。
思路:计算相邻两个数之间的差值,如果要保证较小的话,那么只需要将最大的k个差值去掉,使其单独成为一个区间,合并时值为0.
代码如下:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=3e5+10;
int n,m,k,a,b,c,ans;
int num[N];
int read() {
int y=0,flag=1;
char ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') y=y*10+ch-'0',ch=getchar();
return y*flag;
}
int main(){
n=read(),k=read(),b=read();
for(int i=2;i<=n;i++){
a=read();
num[c++]=a-b;
b=a;
}
sort(num,num+c);
for(int i=0;i<n-k;i++){
ans+=num[i];
}
cout<<ans;
return 0;
}
D: Yet Another Subarray Problem
题意:给一个大小为n的数组,给定m, k,计算子序列的的最大值。
解题思路:由表达式可知最后权值中每隔m个就会减k,那么我们对原数组进行处理每隔m个减去k,枚举右端点mod m的数即可。
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=3e5+10;
ll n,m,k,ans;
ll num[N];
ll read() {
ll y=0,flag=1;
char ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') y=y*10+ch-'0',ch=getchar();
return y*flag;
}
int main(){
n=read(),m=read(),k=read();
for(ll i=1;i<=n;i++)num[i]=read();
for(int j=0;j<m;j++){
ll now=0;
for(int i=1;i<=n;i++){
now+=num[i];
if(i%m==j)ans=max(ans,now-k),now-=k;
now=max(now,(ll)0);
}
}
cout<<ans;
return 0;
}