1. 程式人生 > 實用技巧 >Codeforces Round #683 (Div. 2, by Meet IT)

Codeforces Round #683 (Div. 2, by Meet IT)

A - Add Candies

題面:題面有點繞,總結一下就是有n個長度的陣列,陣列值跟下標值一樣,a[i]=i;然後問你第i次操作,選一個數組中的值,除了它其他都加i,使得陣列值相同,問隨機一種情況

思路:操作n次,輸出1,2,3,4,5 … n即可

B - Numbers Box

題面:給一個n,m的矩陣,有正負,有操作選兩個相鄰的值,同乘-1,求這個矩陣最大的之和

思路:比賽的時候卡了,因為沒想清楚,選了個最小的負數,其實,正解是如果出現奇數個負數,選擇最小的abs值,偶數個負數就肯定能全部變正

比賽的時候隊友飛快過三題,然後我還在卡B,如果不是隊友提醒,可能卡死了

C - Knapsack

題面:給兩個數n,w,給n長度陣列,求數組裡選幾個有沒有w/2~w範圍的值

思路:第一想法揹包,但資料n 2e5,w 1e18,好,肯定不行,換一個,排序然後尺取?,於是寫了一下,就過了

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define lson(x) x<<1
#define rson(x) x<<1|1
#define mod 998244353
using namespace std;
ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1){
            ans*=a;ans%=mod;
        }
        a*=a;a%mod;
        b>>=1;
    }
}
const int N=2e5+10;
int n,m,t;
ll w;
ll dp[N];
struct node{
    int w,num;
    friend bool operator<(const node a,const node b){
        return a.w<b.w;
    }
}we[N];
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%lld",&n,&w);
        int f=1,pos;
        for(int i=0;i<n;i++){
            scanf("%lld",&we[i].w);we[i].num=i+1;
            if(we[i].w*2>=w && we[i].w<=w){
                f=0;pos=i;
            }
        }
        if(!f){
            printf("1\n");
            printf("%d\n",we[pos].num);
            continue;
        }
        sort(we,we+n);
        dp[0]=we[0].w;
        for(int i=1;i<n;i++){
            dp[i]=dp[i-1]+we[i].w;
        }

        for(int i=0;i<n;i++){
            if(dp[i]*2>=w && dp[i]<=w){
                f=0;pos=i;break;
            }
             if(dp[i]*2>=w && dp[i]>w){
                f=2;pos=i;break;
            }
        }
        int pos2=0;
        if(f==2){
            for(int i=0;i<pos;i++){
                while((dp[pos]-dp[i])*2<w){pos++;if(pos>n){break;}}
                if((dp[pos]-dp[i])*2>=w &&(dp[pos]-dp[i])<=w){f=0,pos2=i;break;}
            }
        }
        if(!f){
            printf("%d\n",pos-pos2+1);
            for(int i=pos2;i<=pos;i++){
                printf(i==pos?"%d\n":"%d ",we[i].num);
            }
        }
        else{
            printf("-1\n");
        }
    }
    return 0;
}

D - Catching Cheaters

題面:給n,m兩個小於5000的數字,然後輸入兩個長度為n,m 的字串s1,s2,取兩個子串s1’,s2’長度分別是x,y,求4 * lcs(s1’,s2’)-x-y的最大值

思路:列舉二分貪心wa,因為沒考慮n長度字串的選子串的字母,是個假演算法。所以這道題正解就是dp,每次dp題,貪心貪出事。

那麼方法就是,每次找到相同的字元,就會對前一個狀態+2,如果沒有相同,就會有兩種選擇,移動s1一位,or移動s2一位,每移動一位值就會-1

這樣我們就可以列出狀態轉移方程

**s1[i]==s2[j] 的情況 **比較 dp[i-1][j-1]+2 dp[i-1][j]-1(大於等於0) dp[i][j-1]-1(大於等於0) 哪個大

**s1[i]!=s2[j] 的情況 **比較 dp[i-1][j]-1(大於等於0) dp[i][j-1]-1(大於等於0) 哪個大

然後找dp[i][j]的最大值即可

程式碼:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define lson(x) x<<1
#define rson(x) x<<1|1
#define mod 998244353
using namespace std;
ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1){
            ans*=a;ans%=mod;
        }
        a*=a;a%mod;
        b>>=1;
    }
}
const int N=5e3+10;
int n,m,t;
char s[N],ss[N];
int dp[N][N];
int main(){
    scanf("%d%d",&n,&m);
    scanf("%s",s);
    scanf("%s",ss);
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(s[i]==ss[j]){
                dp[i+1][j+1]=max(dp[i][j]+2,max(max(dp[i+1][j]-1,0),max(dp[i][j+1]-1,0)));
            }
            else{
                dp[i+1][j+1]=max(max(dp[i+1][j]-1,0),max(dp[i][j+1]-1,0));
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
           ans=max(dp[i][j],ans);//cout<<dp[i][j]<<" ";
        }
        //cout<<endl;
    }
    printf("%d\n",ans);
    return 0;
}