非精写版-51nod基础训练(持续更新)

Posted iuk11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非精写版-51nod基础训练(持续更新)相关的知识,希望对你有一定的参考价值。

题目就不赘述了,来源51nod网站。

最长公共子序列LCS

这道题是一道非常好想的二维dp问题,可以在不选当前行,不选当前列的情况下(dp[i+1][j+1]=dp[i][j]+1),若两个字符串中的字符相等,则有在原来的子序列基础上又增加一个字符;若两个字符串中的字符不相等,则寻找到此为止的最大的子序列的长度是多少,把值赋给它。
dp[i][j]:表示第一个字符串取(0,i-1),第二个字符串为(0,j-1),最长的公共子序列是多长。
最后在记录长度的同时,记录这个子序列的长度是怎么加过来的,记录完毕后从终点回溯到起点,用字符串保存回溯中找到的子序列的字符,翻转(因为是从终点到起点),输出。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
int dp[maxn][maxn];
char opp[maxn][maxn];
int main(){ 
    string s,str;
    cin>>s>>str;
    dp[0][0]=0;
    for(int i=0;i<s.size();i++){    
        for(int j=0;j<str.size();j++){
            if(s[i]==str[j]){
                dp[i+1][j+1]=dp[i][j]+1;
                opp[i][j]='x';
            }else{
                if(dp[i][j+1]>dp[i+1][j]){
                    dp[i+1][j+1]=dp[i][j+1];
                    opp[i][j]='d';
                }else{
                    dp[i+1][j+1]=dp[i+1][j];
                    opp[i][j]='r';
                }
            }
        }
    }
    string ans;
    int x=s.size()-1,y=str.size()-1;
    while(x>=0&&y>=0){
        if(opp[x][y]=='x'){
            ans+=s[x];
            x--;
            y--;
        }else if(opp[x][y]=='d'){
            x--;
        }else{
            y--;
        }
    }
    reverse(ans.begin(),ans.end());
    cout<<ans<<endl;
    //system("pause");
	return 0;
}

大数加法(考虑负数)

这就有点灵性了,乱写了一个,模拟的加减法竖式。
调了半天,没考虑前置零,考虑了之后又忘了还有结果为零的情况。
然后就分类讨论就可,我确实是写麻烦了,就当练练大模拟了。

#include<bits/stdc++.h>
using namespace std;
string add(string a,string b){
    int fa=1,fb=1;
    int lena=a.size(),lenb=b.size();
    if(a[0]<'0'||a[0]>'9') fa=-1,a=a.substr(1,lena-1),lena--;
    if(b[0]<'0'||b[0]>'9') fb=-1,b=b.substr(1,lenb-1),lenb--;
    reverse(a.begin(),a.end());
    reverse(b.begin(),b.end());
    string ans;
    int shi=0;
    int tem=0;
    int aa=0,bb=0;
    ans="";
    if((fa>0 && fb<0) || (fa<0 && fb>0)){
        //a-b
        if(lena>lenb || (lena==lenb && a[lena-1]>b[lenb-1])){
            for(int i=0;i<lenb;i++){
                aa=a[i]-'0';
                bb=b[i]-'0';
                tem=aa-bb+shi;
                if(tem<0){
                    tem=tem+10;
                    shi=-1;
                }else{
                    shi=0;
                }
                ans+=(tem+'0');
            }
            for(int i=lenb;i<lena;i++){
                aa=a[i]-'0';
                tem=aa+shi;
                if(tem<0){
                    tem=tem+10;
                    shi=-1;
                }else{
                    shi=0;
                }
                ans+=(tem+'0');
            }
        }else{
            for(int i=0;i<lena;i++){
                aa=a[i]-'0';
                bb=b[i]-'0';
                tem=bb-aa+shi;
                if(tem<0){
                    tem=tem+10;
                    shi=-1;
                }else{
                    shi=0;
                }
                ans+=(tem+'0');
            }
            for(int i=lena;i<lenb;i++){
                bb=b[i]-'0';
                tem=bb+shi;
                if(tem<0){
                    tem=tem+10;
                    shi=-1;
                }else{
                    shi=0;
                }
                ans+=(tem+'0');
            }
            ans+='-';
        }
        //b-a
        
        if(fa<0 && fb>0){
            int len=ans.size();
            if(ans[len-1]=='-') ans=ans.substr(0,len-1);
            else ans+='-';
        }
        
    }else{
        //(a+b) or -(a+b)
        if(lena>lenb){
            for(int i=0;i<lenb;i++){
                aa=a[i]-'0';
                bb=b[i]-'0';
                tem=aa+bb+shi;
                shi=tem/10;
                tem=tem%10;
                ans+=(tem+'0');
            }
            for(int i=lenb;i<lena;i++){
                aa=a[i]-'0';
                tem=aa+shi;
                shi=tem/10;
                tem=tem%10;
                ans+=(tem+'0');
            }
        }else{
            for(int i=0;i<lena;i++){
                aa=a[i]-'0';
                bb=b[i]-'0';
                tem=aa+bb+shi;
                shi=tem/10;
                tem=tem%10;
                ans+=(tem+'0');
            }
            for(int i=lena;i<lenb;i++){
                bb=b[i]-'0';
                tem=bb+shi;
                shi=tem/10;
                tem=tem%10;
                ans+=(tem+'0');
            }
        }
        if(shi) ans+=(shi+'0');
        if(fa<0) ans+='-';
    }
    int cnt=0;
    int f=0;
    int len=ans.size();
    for(int i=len-1;i>=0;i--){
        if(ans[i]=='-'){
            f=1;
            continue;
        }
        if(ans[i]=='0') cnt++;
        else break;
    }
    if(f) cnt++;
    ans=ans.substr(0,len-cnt);
    if(ans==""){
        return "0";
    }
    if(f) ans+='-';
    reverse(ans.begin(),ans.end());
    return ans;
}
int main(){
    string a,b;
    cin>>a>>b;
    string ans;
    ans=add(a,b);
    cout<<ans<<endl;
    //system("pause");
    return 0;
}

day2

逆序对

  • 方法一:归并排序求逆序对。
    归并排序采用分而治之的思想,使复杂度降低到 O ( n l o g n ) O(nlog n) O(nlogn),在每一次回溯的过程中如果发现后面的数比前面的数大,就记录一下要向前移动多少位,思考一下为什么 p = l p=l p=l q = m i d + 1 q=mid+1 q=mid+1
#include<bits/stdc++.h>
using namespace std;
const int maxn=50010;
typedef long long ll;
ll a[maxn],b[maxn];
ll cnt;
void merge_sort(int l,int r){
    if(r-l>0){
        int mid=(l+r)/2;
        int i=l;
        int p=l,q=mid+1;
        merge_sort(l,mid);
        merge_sort(mid+1,r);
        while(p<=mid || q<=r){
            if(q>r||(p<=mid&&a[p]<=a[q])){
                b[i++]=a[p++];
            }else{
                b[i++]=a[q++];
                cnt=cnt+mid-p+1;
            }
        }
        for(i=l;i<=r;i++){
            a[i]=b[i];
        }
    }
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    merge_sort(1,n);
    cout<<cnt<<endl;
    //system("pause");
    return 0;
}
  • 方法二:树状数组求逆序对
    看了一篇好博客
    里面离散化解释的特别好,如果给定的数值很分散,跨度很大,我们就用一个新数组储存这些数值的下标,根据它们值的大小对下标排序。
    思考:
    接下来就是由大到小排序,(我们现在有的是对 a [ ] a[] a[]数组排好序的对应的下标数组 b [ ] b[] b[])按照这个逻辑,实际我们是在寻找数列中的正序对,x进入数组后要去找有多少个数是比它小的(因为如果有,一定是在x之前进入树状数组,一定是排在x之前的数,自然也一定是个正序对)。
    那怎么找x之前有多少个比它小的数,在每个数x放入数组之时,更新[x,n]中的所有二的整数倍的数组下标中的值,记录在t[]数组中。
    那么 t [ x ] t[x] t[x] 就是在[1,x]中已经存在了多少个小于x的数(好像也不应该这么说,[x+1,n]也更新了,但是我们只用到[1,x]的区间)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=50010;
typedef long long ll;
ll a[maxn],b[maxn];
ll ans;
ll t[maxn];
int n;
int lowbit(int x){
    return x&-x;
}
void add(int x){
    while(x<=n){
        t[x]++;
        x+=lowbit(x);
    }
}
ll sum(int x){
    ll res=0;
    while(x>=1){
        res+=t[x];
        x-=lowbit(x);
    }
    return res;
}
bool cmp(int x,int y){
    if(a[x]==a[y]) return x>y;
    return a[x]>a[y];
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=i;
    }
    sort(b+1,b+1+n,cmp);
    f

以上是关于非精写版-51nod基础训练(持续更新)的主要内容,如果未能解决你的问题,请参考以下文章

非精写版-51nod基础训练

非精写版-51nod基础训练

非精写版-51nod基础训练

非精写版-51nod基础训练(终)

[蓝桥杯Python]算法练习算法基础算法训练算法模板(持续更新)

回归 | js实用代码片段的封装与总结(持续更新中...)