目录
最长上升子序列
题目描述
给定N 个数,求这N 个数的最长上升子序列的长度。
什么是最长上升子序列?
就是给你一个序列,请你在其中求出一段不断严格上升的部分,它不一定要连续。
比如:2,3,4,7
和 2,3,4,6
就是序列 2 5 3 4 1 7 6
的两种选取方案。最长的长度是 4.
输入:
第一行一个整数 1≤n≤105
接下来一行 n 个用空格隔开的整数 ai,0≤ai≤106
输出:
输出一个整数,表示最长上升子序列的长度
样例:
|7
|2 5 3 4 1 7 6
输出:
|4
题解
结合动态规划
f[i]是以编号为i结尾的最长上升子序列
f[i]=max(f[j]+1),要求j<i并且a[j]<a[i]
用树状数组保存f[i]的值
找出f1到f[i-1]的最大值,再找出f1到fn的最大值,即为答案
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
ll c[maxn],a[maxn];
ll maxa=0;
ll lowbit(ll t){
return t&(-t);
}
ll getsum(ll x){
ll ans=0;
for(ll i=x;i>=1;i-=lowbit(i)){
ans=max(ans,c[i]);
}
return ans;
}
void change(ll x,ll y){
for(ll i=x;i<=maxa;i+=lowbit(i)){
c[i]=max(c[i],y);
}
}
int main() {
ll n;
scanf("%lld",&n);
for(ll i=1;i<=n;i++){
scanf("%lld",&a[i]);
a[i]++;
maxa=max(maxa,a[i]);
}
for(ll i=1;i<=n;i++){
ll k=getsum(a[i]-1);
change(a[i],k+1);
}
printf("%lld",getsum(maxa));
return 0;
}
区间改值和单点查询
题目描述
给定数组a1,a2...an,进行q次操作,操作有两种:
1 l r k
:将ai ~ ar 每个数都加上 k;
2 k
:输出ak
输入:
第一行:输入两个数 n,q,表示给定数组的长度和操作数
第二行:输入n个数,表示长度为n的给定数组
接下来q行:每行输入表示如题的某一种操作
输出:
对于每个2操作,输出对应结果
样例:
|3 2
|1 2 3
|1 1 3 1
|2 2
输出:
|3
题解
用树状数组实现差分,
让l到r的区间内都加上k,实则运用查分思想,让树状数组l到n都加上k,r+1到n都减去k
最后求出差分数组的前缀和,即为原数组
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
ll c[maxn],a[maxn];
ll maxa=0,n,q;
ll lowbit(ll t){
return t&(-t);
}
ll getsum(ll x){
ll ans=0;
for(ll i=x;i>0;i-=lowbit(i)){
ans+=c[i];
}
return ans;
}
void change(ll l,ll r,ll k){
for(ll i=l;i<=n;i+=lowbit(i)) c[i]+=k;
for(ll i=r+1;i<=n;i+=lowbit(i)) c[i]-=k;
}
int main() {
scanf("%lld%lld",&n,&q);
for(ll i=1;i<=n;i++){
scanf("%lld",&a[i]);
change(i,i,a[i]);
}
while(q--){
ll p;
scanf("%lld",&p);
if(p==1){
ll l,r,k;
scanf("%lld%lld%lld",&l,&r,&k);
change(l,r,k);
}
if(p==2){
ll o;
scanf("%lld",&o);
printf("%lld\n",getsum(o));
}
}
return 0;
}
区间改值和区间求和
题目描述
给定数组a1,a2...an,进行q次操作,操作有两种:
1 l r k
:将al ~ ar 每个数都加上 k;
2 l r
:求al+...+ar
输入:
第一行:输入两个数 n,q,表示给定数组的长度和操作数
第二行:输入n个数,表示长度为n的给定数组
接下来q行:每行输入表示如题的某一种操作
输出:
对于每个2操作,输出对应结果
样例:
|5 3
|2 6 6 1 1
|2 1 4
|1 2 5 10
|2 1 3
输出:
|15
|34
题解
∑rai=i=1∑rai−i=1∑l−1ai 应该能看懂吧
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
ll c[maxn],a[maxn],c2[maxn];
ll maxa=0,n,q;
ll lowbit(ll t){
return t&(-t);
}
ll getsum(ll p){
ll ans=0;
for(ll i=p;i>0;i-=lowbit(i)){
ans+=(p+1)*c[i]-c2[i];
}
return ans;
}
void change(ll l,ll r,ll k){
for(ll i=l;i<=n;i+=lowbit(i)){
c[i]+=k; c2[i]+=k*l;
}
for(ll i=r+1;i<=n;i+=lowbit(i)){
c[i]-=k; c2[i]-=k*(r+1);
}
}
int main() {
scanf("%lld%lld",&n,&q);
for(ll i=1;i<=n;i++){
scanf("%lld",&a[i]);
change(i,i,a[i]);
}
while(q--){
ll p;
scanf("%lld",&p);
if(p==1){
ll l,r,k;
scanf("%lld%lld%lld",&l,&r,&k);
change(l,r,k);
}
if(p==2){
ll l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",getsum(r)-getsum(l-1));
}
}
return 0;
}