#A. 最大子段和

最大子段和(正常)

for(int i=1;i<=n;i++) sum[i]=max(sum[i-1]+in[i],in[i]);
  • sum[i]表示以第i个数为结尾的最大子段和,可以由前一个最大子段和转移过来(sum[i1]+in[i]),也可以只包含自己(in[i]);

本题

  • fr[i]表示以前i个数的最大子段和,ba[i]表示以第i个数为开头,结尾为n的最大子段和(求法与上面类似);

  • 再做一次处理,分别用fr[i1],ba[i+1]更新fr[i],ba[i],使得fr[i]表示以第i个数为结尾的最大子段和,ba[i]表示以第i个数为开头的最大子段和;

  • 因为两段不相交,所以i把序列分成1ii+1n两部分

  • 枚举位置i,i位置的最大子段和为fr[i]+ba[i+1];

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n;
int maxi;
int in[N];
int fr[N],ba[N];
signed main(){
// freopen("1.in","r",stdin);
cin>>n;
for(int i=1;i<=n;i++) cin>>in[i];
fr[1]=in[1];
for(int i=2;i<=n;i++) fr[i]=max(fr[i-1]+in[i],in[i]); //1~i的最大子段和;
for(int i=2;i<=n;i++) fr[i]=max(fr[i-1],fr[i]); //以第i个数结尾的最大子段和;
ba[n]=in[n];
for(int i=n-1;i>=1;i--) ba[i]=max(ba[i+1]+in[i],in[i]); //i~n的最大子段和;
for(int i=n-1;i>=1;i--) ba[i]=max(ba[i+1],ba[i]); //以第i个数开头的最大子段和;
maxi=fr[1]+ba[2];
for(int i=2;i<=n-1;i++) maxi=max(maxi,fr[i]+ba[i+1]);
cout<<maxi<<"\n";
}

出处 P2642 双子序列最大和

 

#B. 等差数列

二阶等差数列(好像和下面没啥关系)

  • 后项与前项的差是等差数列
1 3 7 13 21 31 ->原数列
2 4 6 8 10 ->后项与前项的差
2 2 2 2 ->差的差相同(等差数列)

如何实现在一个区间上加上一个等差数列的操作

  • 给区间[2,6]加上首项为s,末项为e,差为d的等差数列
下标 a1 a2 a3 a4 a5 a6 a7 a8
原数组的变化 0 s s+d s+2*d s+3*d e 0 0
一阶差分 0 s d d d d -e 0
二阶差分 0 s d-s 0 0 0 -e-d e
  • 实质:给一阶差分数组再做一次差分

    • 原因:一阶差分后有好多位置都是公差d,再差分一次就可以消掉
  • 得出:

    • 给数组[l,r]区间加上首项为s,末项为e,差为d的等差数列的操作为:
    a[l]+=s; a[l+1]+=d-s; a[r+1]-=e+d; a[r+2]+=e;

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+10;
int n,m;
int in[N];
int l,r,s,e;
int eq;
int res;
signed main(){
// freopen("1.in","r",stdin);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>l>>r>>s>>e;
eq=(e-s)/(r-l);
in[l]+=s; in[l+1]+=-s+eq;
in[r+1]-=e+eq; in[r+2]+=e;
}
for(int i=1;i<=n+1;i++) in[i]+=in[i-1];
for(int i=1;i<=n+1;i++) in[i]+=in[i-1];
for(int i=1;i<=n;i++) res^=in[i];
cout<<res<<"\n";
}

出处 P4231 三步必杀

 

#C. 可爱序列

状态设计

  • dp[i][j][k][0/1]

  • 第一维表示考虑到了第i个数

  • 第二维表示第i个数填j

  • 第三维表示前i个数的和为k

  • 第四维表示增减关系(0为 , 1为<)

转移

for(int i=1;i<=n;i++){
int l=0,r=40;
if(in[i]!=-1) l=r=in[i];
for(int j=l;j<=r;j++){ //枚举第i个数的范围
for(int k=j*(i-1);k<=40*(i-1);k++){ //前(i-1)个数的和的范围
//因为<序列中每个元素都不大于之前的数的平均值>,所以前(i-1)个数的平均值至少为j,和至少为(i-1)*j
for(int z=0;z<=j;z++) dp[i][j][j+k][0]=(dp[i][j][j+k][0]+dp[i-1][z][k][0]+dp[i-1][z][k][1])%MOD;
//第i-1个数<=第i个数
for(int z=j+1;z<=40;z++) dp[i][j][j+k][1]=(dp[i][j][j+k][1]+dp[i-1][z][k][0])%MOD;
//第i-1个数>第i个数
//因为<没有三个连续的递减的数>,所以:
//如果i>=i-1,i-1相对i-2即可增也可减;
//如果i<i-1,i-1相对i-2只能增,否则会出现连续递减
}
}
}

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=1e9+7;
int n,ans;
int in[41];
int dp[41][41][1601][2];
signed main(){
// freopen("1.in","r",stdin);
cin>>n;
dp[0][0][0][0]=1;
for(int i=1;i<=n;i++) cin>>in[i];
for(int i=1;i<=n;i++){
int l=0,r=40;
if(in[i]!=-1) l=r=in[i];
for(int j=l;j<=r;j++){
for(int k=j*(i-1);k<=40*(i-1);k++){
for(int z=0;z<=j;z++) dp[i][j][j+k][0]=(dp[i][j][j+k][0]+dp[i-1][z][k][0]+dp[i-1][z][k][1])%MOD;
for(int z=j+1;z<=40;z++) dp[i][j][j+k][1]=(dp[i][j][j+k][1]+dp[i-1][z][k][0])%MOD;
}
}
}
for(int i=0;i<=40;i++){
for(int j=0;j<=40*n;j++){
ans=(ans+dp[n][i][j][0]+dp[n][i][j][1])%MOD;
}
}
cout<<ans<<"\n";
}

 

#D. 石子游戏

  • (i,j)的石子1,导致(i+1,j),(i,j+1)的石子+1

  • 画图为:

1 1 1 1 1 1
1 2 3 4 5
1 3 6 10
1 4 10
1 5
1
  • 发现它其实就是个杨辉三角

  • 用组合公式表示为:

1 2 3 4 5 6
1 C00 C11 C22 C33 C44 C55
2 C10 C21 C32 C43 C54
3 C20 C31 C42 C53
4 C30 C41 C52
4 C40 C51
6 C50
  • 第i行第j列的数可以表示为Ci+j2j1

  • f(i,j)=Ci+j2j1

f(i,j+1)+f(i+1,j)=Ci+j1j+Ci+j1j1=Ci+jj

f(i,j)=Cai+i1ai1

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
const int MOD=1e9+7;
int n;
int jie[N];
int inv[N];
int in[N];
int ans;
int q_pow(int a,int b){
int ans=1;
while(b){
if(b&1) ans=ans*a%MOD;
a=a*a%MOD;
b>>=1;
}
return ans%MOD;
}
int C(int a,int b){
if(b<0) return 0;
return jie[a]%MOD*inv[b]%MOD*inv[a-b]%MOD;
}
signed main(){
// freopen("1.in","r",stdin);
cin>>n;
n++;
for(int i=1;i<=n;i++) cin>>in[i];
jie[0]=1; inv[0]=1;
for(int i=1;i<N;i++){
jie[i]=jie[i-1]*i%MOD;
inv[i]=q_pow(jie[i],MOD-2);
}
for(int i=1;i<=n;i++) ans=(ans+C(in[i]+i-1,in[i]-1))%MOD;
cout<<ans<<"\n";
}

出处 Placing Jinas

 

posted on   Bubble_e  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话



点击右上角即可分享
微信分享提示