蓝桥杯复习

动态规划

区间DP

https://www.acwing.com/problem/content/284/

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=305;
int f[N][N];//f(i,j) 在区间i,j里的最小代价
int s[N],n;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>s[i];
        s[i]+=s[i-1];//维护前缀和
    }
    for(int len=2;len<=n;len++){//枚举长度
        for(int i=1;i+len-1<=n;i++){//枚举左端点
            int j=i+len-1;//枚举右端点
            f[i][j]=1e8;
            for(int k=i;k<j;k++){
                f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
            }
        }
    }
    cout<<f[1][n]<<endl;
  return 0;
}
//  freopen("testdata.in", "r", stdin);

线性DP

最长公共子序列
https://www.acwing.com/problem/content/899/

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e3+5;
int n,m;
char a[N],b[N];
int f[N][N];//f(i,j) 字符串1 1到i 字符串2 2到j的最大公共子序列
int main()
{
    cin>>n>>m>>a+1>>b+1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            f[i][j]=max(f[i-1][j],f[i][j-1]);
            if(a[i]==b[j]){
                f[i][j]=max(f[i][j],1+f[i-1][j-1]);
            }
        }
    }
    cout<<f[n][m];
}

最长上升子序列
https://www.acwing.com/problem/content/897/

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e3+5;
int a[N];
int f[N],n;//所有以i结尾的最大上升子序列
int main()
{   
    cin>>n;
    for (int i = 1; i <= n; i ++ ){
        cin>>a[i];
    }
    for(int i=1;i<=n;i++){
        f[i]=1;
        for(int j=1;j<i;j++){
            if(a[j]<a[i]){
                f[i]=max(f[i],f[j]+1);
            }
        }
    }
    int res=0;
    for(int i=1;i<=n;i++){
        res=max(res,f[i]);
    }
    cout<<res<<endl;
}

Dilworth定理:通俗解释: 把一个数列划分成最少的最长不升子序列的数目就等于这个数列的最长上升子序列的长度(LIS)

最短编辑距离

https://www.acwing.com/problem/content/description/904/

#include <iostream>
#include <cstring>
#include <algorithm>
const int N = 1e3+5;
char a[N],b[N];
int n,m;
int f[N][N];//f(i,j) 从a的1-i变到b的1-j的最小操作
using namespace std;
int main()
{
    cin>>n>>(a+1)>>m>>(b+1);
    //初始化f数组
    for(int i=1;i<=n;i++) f[i][0]=i;
    for(int j=1;j<=m;j++) f[0][j]=j;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int temp;
            if(a[i]==b[j]) temp=0;//如果i,j相同就不需要变化这个操作,否则就需要
            else temp=1;
            //取3种操作的最小值
            f[i][j]=min(f[i-1][j]+1,min(f[i][j-1]+1,f[i-1][j-1]+temp));
        }
    }
    cout<<f[n][m]<<endl;
}

背包专题

https://www.cnblogs.com/OfflineBoy/p/14526380.html

前缀和差分

一维前缀和
https://www.acwing.com/problem/content/797/

#include <iostream>
#include <cstring>
#include <algorithm>
const int N = 1e5+5;
using namespace std;
int s[N];
int n,m;
int main()
{
    cin>>n>>m;
    for (int i = 1; i <= n; i ++ ){
        cin>>s[i];
        s[i]+=s[i-1];
    }
    while (m -- ){
        int l,r;
        cin>>l>>r;
        printf("%d\n",s[r]-s[l-1]);
    }
}

二维前缀和
https://www.acwing.com/problem/content/798/

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e3+5;
int s[N][N];//s[i][j]该点左上角的矩阵前缀和
int n,m,q;
int get_prefix_sum(int x1,int y1,int x2,int y2){
    return s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
}
int main()
{   
    cin>>n>>m>>q;
    for (int i = 1; i <= n; i ++ ){
        for(int j = 1;j <= m;j ++){
            cin>>s[i][j];
            s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
        }
    }
    while(q--){
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        cout<<get_prefix_sum(x1,y1,x2,y2)<<endl;
    }
    return 0;
}

一维差分
https://www.acwing.com/problem/content/799/

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
const int N=1e5+5;
int n,m;
int a[N],b[N];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=a[i]-a[i-1];//构建差分
    }
    while(m--){
        int l,r,c;
        cin>>l>>r>>c;
        b[l]+=c;
        b[r+1]-=c;
    }
    //通过求b数列的前缀和来获得a数列
    for(int i=1;i<=n;i++){
        a[i]=a[i-1]+b[i];
        cout<<a[i]<<" ";
    }
  return 0;
}
//  freopen("testdata.in", "r", stdin);

二维差分
https://www.acwing.com/problem/content/800/

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
int n,m,q;
int a[1005][1005];
int b[1005][1005];
void insert(int x1,int y1,int x2,int y2,int c){
    b[x1][y1]+=c;
    b[x2+1][y1]-=c;
    b[x1][y2+1]-=c;
    b[x2+1][y2+1]+=c;
}
int main(){
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            insert(i,j,i,j,a[i][j]);
        }
    }
    while(q--){
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        insert(x1,y1,x2,y2,c);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            printf("%d ",b[i][j]);
        }
        printf("\n");
    }

  return 0;
}
//  freopen("testdata.in", "r", stdin);

二分模板

整数二分模板

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

https://www.acwing.com/problem/content/791/

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
const int Maxn=1e5+5;
int a[Maxn];
int n,q,k;
//不小于
//区间被划为(l,mid),(mid+1,r)
int fun1(int l,int r,int k){
    while(l<r){
        int mid=(l+r)>>1;
        if(a[mid]<k) l=mid+1;
        else r=mid;
    }
    if(a[l]!=k) return -1;
    return l;
}
//不大于
//区间被划为了(l,mid-1) (mid,r)
int fun2(int l,int r,int k){
    while(l<r){
        int mid=(l+r+1)>>1;
        if(a[mid]>k) r=mid-1;
        else l=mid;
    }
    if(a[l]!=k) return -1;
    return l;
}
int main(){
    cin>>n>>q;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    while(q--){
        cin>>k;
        cout<<fun1(0,n-1,k)<<" "<<fun2(0,n-1,k)<<endl;
    }
  return 0;
}

//  freopen("testdata.in", "r", stdin);

lower_bound( )和upper_bound( )

https://www.cnblogs.com/OfflineBoy/p/13735280.html

小数二分

https://www.acwing.com/problem/content/792/

/*
double bsearch_3(double l, double r)
{
    const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}
*/
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
double n;
double fun(double l,double r){
    const double eps=1e-8;
    while(r-l>eps){
        double mid=(l+r)/2;
        if(mid*mid*mid<=n) l=mid;
        else r=mid;
    }
    return l;
}
int main(){
    cin>>n;
    printf("%.6lf\n", fun(-100.0,100.0));
  return 0;
}

//  freopen("testdata.in", "r", stdin);

posted @ 2021-04-16 20:37  一个经常掉线的人  阅读(69)  评论(0)    收藏  举报