Zut_round 8(多维dp1)

A

/*   Author : Rshs   */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
char a[MXN],b[MXN];
int dp[1005][1005];
int main(){
    cin>>(a+1)>>(b+1);
    int la=strlen(a+1),lb=strlen(b+1);
    for(int i=1;i<=la;i++) dp[i][0]=i;
    for(int i=1;i<=lb;i++) dp[0][i]=i;
    for(int i=1;i<=la;i++){
        for(int j=1;j<=lb;j++){
            if(a[i]==b[j]){
                dp[i][j]=dp[i-1][j-1];
            }
            else {
                dp[i][j]=min(dp[i-1][j],min(dp[i][j-1],dp[i-1][j-1]))+1;
            }
        }
    }
    cout<<dp[la][lb];
    return 0;
}

B

dp转移的时候记录一下前驱就可以输出路径了。

/*   Author : Rshs   */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
char a[MXN],b[MXN];
int dp[1005][1005];
PII pr[1005][1005];
int main(){
    cin>>(a+1)>>(b+1);
    int la=strlen(a+1),lb=strlen(b+1);
    for(int i=1;i<=la;i++){
        for(int j=1;j<=lb;j++){
            if(a[i]==b[j]){
                dp[i][j]=dp[i-1][j-1]+1;
                pr[i][j]=MP(i-1,j-1);
            }
            else {
               if(dp[i-1][j]>dp[i][j-1]) dp[i][j]=dp[i-1][j],pr[i][j]=MP(i-1,j);
               else  dp[i][j]=dp[i][j-1],pr[i][j]=MP(i,j-1);
            }
        }
    }
    int ans=0;
    PII u;
    for(int i=1;i<=la;i++){
        for(int j=1;j<=lb;j++){
            if(dp[i][j]>ans)ans=dp[i][j],u=MP(i,j);
        }
    }
    vector<char>v;
    while(ans){
        if(a[u.FI]==b[u.SE]){
            v.push_back(a[u.FI]);
            ans--;
        }
         u=pr[u.FI][u.SE];
    }
    reverse(v.begin(),v.end());
    for(auto i:v) cout<<i;
    return 0;
}

C

自然而然想到要做成环,让S在末尾加上S的前20个。
有两个注意点:
1.注意S的长度小于10的时候,再按照上述方法操作,输入的匹配串可能会多次利用S的字母,这个时候直接暴力枚举S做成的len(S)种环。
2.注意是substring,注意转移方程和初始化。

/*   Author : Rshs   */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
char s[MXN];
char tt[MXN];
int dp[MXN][20];

int main(){
    while(scanf("%s",s+1)!=EOF){
        int n=strlen(s+1);
        if(n<=20){
            int q;cin>>q;
            int ans=INT_MAX;string u,t;
            while(q--){
                cin>>(t);
                int m=t.length();
                for(int _=0;_<n;_++){
                    for(int j=0;j<n;j++){
                        tt[(j+_)%n]=s[j+1];
                    }
                    for(int i=1;i<=n;i++) dp[i][0]=0;
                    for(int i=1;i<=m;i++) dp[0][i]=i;
                    for(int i=1;i<=n;i++){
                        for(int j=1;j<=m;j++){
                            if(tt[i-1]==t[j-1]){
                                dp[i][j]=dp[i-1][j-1];
                            }
                            else {
                                dp[i][j]=dp[i-1][j]+1;
                                dp[i][j]=min(dp[i][j],dp[i][j-1]+1);
                                dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1);
                            }
                            if(j==m){
                                if(dp[i][m]<ans) ans=dp[i][m],u=t;
                                if(dp[i][m]==ans&&t<u) u=t;
                            }
                        }
                    }
                }
            }
            cout<<u<< ' '<<ans<<'\n';
            continue;
        }
        int add=min(20,n);
        for(int i=n+1;i<=n+add;i++){
            s[i]=s[i-n];
        }
        n=n+add;
        int q;cin>>q;
        int ans=INT_MAX;string u,t;
        while(q--){
            cin>>(t);
            int m=t.length();
            for(int i=1;i<=n;i++) dp[i][0]=0;
            for(int i=1;i<=m;i++) dp[0][i]=i;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    if(s[i]==t[j-1]){
                        dp[i][j]=dp[i-1][j-1];
                    }
                    else {
                        dp[i][j]=dp[i-1][j]+1;
                        dp[i][j]=min(dp[i][j],dp[i][j-1]+1);
                        dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1);
                    }
                    if(j==m){
                        if(dp[i][m]<ans) ans=dp[i][m],u=t;
                        if(dp[i][m]==ans&&t<u) u=t;
                    }
                }
            }
        }
        cout<<u<< ' '<<ans<<'\n';
    }
    return 0;
}

D

d p [ i ] [ j ] dp[i][j] dp[i][j]:a的前i位和b的前j位可以组成的种类数。
容斥种类数。

/*   Author : Rshs   */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
int a[MXN],b[MXN];
LL dp[1005][1005];
int main(){
    int n,m;
    while(cin>>n>>m){
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)scanf("%d",&b[i]);
        dp[0][0]=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i]==b[j]) dp[i][j]=(1+dp[i-1][j-1]+dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%mod;
                else dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%mod;
            }
        }
        cout<<(dp[n][m]%mod+mod)%mod<<'\n';
    }
    return 0;
}

E

当n=1是,我是0,wa了。

/*   Author : Rshs   */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;

int main(){
    int n;cin>>n;
    if(n>36) cout<<-1;
    else {
        while(n>=2){
            n-=2;
            cout<<8;
        }
        if(n==1){
            cout<<6;
        }
    }
    return 0;
}

F

取最大值的最小值,无需分类讨论。

/*   Author : Rshs   */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
int a[MXN],b[MXN];
int main(){
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int j=1;j<=m;j++) cin>>b[j];
    LL mi=LLONG_MAX;
    for(int i=1;i<=n;i++){
        LL mx=LLONG_MIN;
        for(int j=1;j<=n;j++){
            if(i==j)continue;
            for(int k=1;k<=m;k++){
                mx=max(mx,(LL)a[j]*(LL)b[k]);
            }
        }
        mi=min(mx,mi);
    }
    cout<<mi;
    return 0;
}

G

没怎么动脑子,暴力考虑反转不反转。
用区间dp,O(1)转移代价。

/*   Author : Rshs   */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
int a[MXN],p2[MXN],p1[MXN];
int dp[2005][2005],c[2005][2005];
int main(){
    int n;cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n+1;i++){
        p2[i]=p2[i-1]+(a[i]==2);
        p1[i]=p1[i-1]+(a[i]==1);
    }
    for(int i=1;i<=n;i++) c[i][i]=1;
    for(int i=2;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(j+i-1>n) break;
            int r=j+i-1,l=j;
            if(a[r]==2) c[l][r]=c[l][r-1]+1;
            else c[l][r]=c[l][r-1];
            c[l][r]=max(c[l][r],p2[r]-p2[l-1]);
            c[l][r]=max(c[l][r],p1[r]-p1[l-1]);
        }
    }
    for(int i=1;i<=n;i++) dp[i][i]=1;
    for(int i=2;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(j+i-1>n) break;
            int r=j+i-1,l=j;
            if(a[r]==1) dp[l][r]=dp[l][r-1]+1;
            else dp[l][r]=dp[l][r-1];
            dp[l][r]=max(dp[l][r],p2[r]-p2[l-1]);
            dp[l][r]=max(dp[l][r],p1[r]-p1[l-1]);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            ans=max(ans,p1[i-1]+p2[n]-p2[j]+max(dp[i][j],c[i][j]));
        }
    }
    cout<<ans<<'\n';
    return 0;
}

H

f 0 = p + k ∗ g 0 f_0=p+k*g_0 f0=p+kg0
f 1 = g 0 + k ∗ g 1 f_1=g_0+k*g_1 f1=g0+kg1
f 2 = g 1 + k ∗ g 2 f_2=g_1+k*g_2 f2=g1+kg2

f x = g x − 1 + k ∗ g x f_x=g_{x-1}+k*g_x fx=gx1+kgx
然后方程代换消去g可以得到:
p = f 0 − k ∗ f 1 + k 2 ∗ f 2 . . . + k x ∗ f k p=f_0-k*f_1+k^2*f_2...+k^x*f_k p=f0kf1+k2f2...+kxfk
然后这个东西就是负进制(-k进制)。
问题转化为求p的-k进制。
具体做法看代码。

/*   Author : Rshs   */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define LDB long double
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const LDB pai = acos(-1.0L);
const LDB eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;

int main(){
    LL p,k;cin>>p>>k;
    vector<LL>v;
    while(p){//和正数进制差不多
        LL s=p/(-k);
        LL y=p%(-k);
        if(y<0) y+=k,s++; //不能出现负数
        if(y>k) {puts("-1");return  0;}
        v.push_back(y);
        p=s;
    }
    cout<<SZ(v)<<'\n';
    for(auto i:v)cout<<i<< ' ' ;
    return 0;
}

I

我写撒点,写的稀碎。。。但是精度有问题好像,而且t了。
正解用平面上的欧拉公式。先记个结论。
平面上的欧拉公式:V - E + R = C + 1,其中 V(vertex) 表示交点数目,E(edge) 表示边数,R(region) 表示区域数,C(connection) 用来分割的线所构成的连通块个数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值