비정필판 - 51nod 기초 훈련(지속 업데이트)

98901 단어 동메달
제목은 군말하지 않겠습니다. 출처는 51nod 사이트입니다.

최대 공통 하위 시퀀스 LCS


이 문제는 매우 보고 싶은 2차원 dp문제로 앞줄을 선택하지 않고 앞줄을 선택하지 않는 상황에서(dp[i+1][j+1]=dp[i][j]+1) 두 문자열의 문자가 같으면 원래의 서열을 바탕으로 한 문자를 추가할 수 있다.만약 두 문자열의 문자가 같지 않다면, 지금까지의 가장 큰 서열의 길이가 얼마인지 찾아서 값을 부여하십시오.dp[i][j]: 첫 번째 문자열(0,i-1)을 나타내고 두 번째 문자열(0,j-1)을 나타내며 가장 긴 공통 서열은 얼마나 깁니까?마지막으로 길이를 기록하는 동시에 이 서열의 길이가 어떻게 더해졌는지 기록한다. 기록이 끝난 후에 종점에서 기점으로 거슬러 올라가 문자열로 거슬러 올라가서 찾은 서열의 문자를 저장하고 뒤집기(종점에서 기점까지)이기 때문에 출력한다.
#include
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
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

역순

  • 방법1: 정렬을 병합하여 역순을 구한다.병합 서열은 분별하여 다스리는 사상을 채택하여 복잡도를 O(n l o g n) O(nlog n) O(nlogn)로 낮추고, 매번 거슬러 올라가는 과정에서 뒤의 수가 앞의 수보다 크다는 것을 발견하면 몇 자리를 앞으로 이동해야 하는지 기록하고, 왜 p=l p=l와 q=m i d+1 q=mid+1 q=mid+1 q=mid+1
  • #include
    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;
    }
    
  • 방법2: 트리 수조의 역순을 구하는 것은 좋은 블로그의 이산화 해석을 보는 데 특히 좋다. 만약에 주어진 수치가 분산되고 경계가 크다면 우리는 새로운 수조로 이 수치의 하표를 저장하고 그 값의 크기에 따라 하표를 정렬한다.사고: 다음은 큰 그룹에서 작은 그룹으로 나뉜다. (우리가 지금 가지고 있는 것은 a[]a[]a[]수조에 대한 서열에 대응하는 하위 그룹 b[]b[]b[]) 이 논리에 따르면 실제적으로 우리는 수열의 정렬을 찾고 있다. x가 수조에 들어간 후에 몇 개의 숫자가 그것보다 작은지 찾아야 한다. (만약에 있다면 반드시 x가 나무 모양의 수조에 들어가기 전에 반드시 x가 있는 숫자이고 자연히 정렬이 맞기 때문이다)그러면 x를 찾기 전에 그것보다 작은 수가 얼마나 많은지, 각 수 x가 수조에 들어갈 때, [x, n]의 모든 2의 정수 배의 수조 아래에 표시된 값을 업데이트하여 t[]수조에 기록합니다.그러면 t[x]t[x]t[x]는 [1,x]에 x보다 작은 수가 몇 개 존재하는 것 같다. (이렇게 말해서는 안 될 것 같다. [x+1,n]도 업데이트되었지만 우리는 [1,x]의 구간까지만 사용한다.
  • #include
    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);
        for(int i=1;i<=n;i++){
         
            add(b[i]);
            ans+=sum(b[i]-1);
        }
        cout<<ans<<endl;
        return 0;
    }
    

    대수 곱셈


    여전히 시뮬레이션을 해서 쓸 때 약간의 착오가 생겼다.
    terminate called after throwing an instance of ‘std::out_of_range’ what(): basic_string::substr 솔루션:substr 방법의 전후 코드를 찾아서 가능한 경계 조건을 배제합니다.
    다른 건 잘 됐어.
    #include
    using namespace std;
    const int maxn=50010;
    typedef long long ll;
    string add(string a,string b){
         
        reverse(a.begin(),a.end());
        reverse(b.begin(),b.end());
        string ans;
        int shi=0;
        int tem=0;
        int aa=0,bb=0;
        int lena=a.size(),lenb=b.size();
        ans="";
        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');
        int cnt=0;
        int len=ans.size();
        for(int i=len-1;i>=0;i--){
         
            if(ans[i]=='0') cnt++;
            else break;
        }
        ans=ans.substr(0,len-cnt);
        if(ans==""){
         
            return "0";
        }
        reverse(ans.begin(),ans.end());
        return ans;
    }
    string mul(string a,string b){
         
        int fa=1,fb=1;
        int lena=a.size(),lenb=b.size();
        if(a[0]=='-'){
         fa=-1;a.substr(1,lena-1);lena--;}
        if(b[0]=='-'){
         fb=-1;b.substr(1,lenb-1);lenb--;}
        reverse(a.begin(),a.end());
        reverse(b.begin(),b.end());
        if(lenb>lena){
         
            string temp=a;
            a=b;
            b=temp;
            int tt=lena;
            lena=lenb;
            lenb=tt;
        }
        vector<string> ve;
        int num=0;
        for(int i=0;i<lenb;i++){
         
            string ans;
            int p=b[i]-'0';
            int shi=0;
            for(int j=0;j<lena;j++){
         
                num=(a[j]-'0')*p+shi;
                shi=num/10;
                num%=10;
                ans+=(num+'0');
            }
            string sh;
            sh="";
            sh=(shi+'0');
            ans+=sh;
            reverse(ans.begin(),ans.end());
            for(int j=0;j<i;j++){
         
                ans+="0";
            }
            ve.push_back(ans);
            shi=0;
            num=0;
        }
        string s,str;
        s=ve[0];
        for(int i=1;i<ve.size();i++){
         
            s=add(s,ve[i]);
        }
        int cnt=0;
        int len=s.size();
        for(int i=0;i<len;i++){
         
            if(s[i]=='0') cnt++;
            else break;
        }
        s=s.substr(cnt,len-cnt);
        if(s==""){
         
            return "0";
        }
        if(fa<0 && fb<0){
         
            ;
        }else if(fa>0 && fb>0){
         
            ;
        }else{
         
            str="-";
        }
        str+=s;
        return str;
    }
    int main(){
         
        string a,b;
        cin>>a>>b;
        cout<<mul(a,b)<<endl;
        //system("pause");
        return 0;
    }
    

    day3

    N의 계승


    아이디어는 A [i] A [i] A [i] A [i] 수조로 저장하고 각 수조에 14자리수를 저장하며 연산을 롱롱롱의 범위에서 제어할 수 있다. 첫 번째 순환은 어느 수를 곱해야 하는지(1~n 중), 두 번째 순환은 몇 개의 A [i] A [i] A [i] A [i]를 사용했고 l l개를 사용했다.ccc는 저장할 수 없는 진위수를 저장한다. 만약 있다면 다음 A[i] A[i] A[i]에 저장하고 ll l로 업데이트한 다음에 순환 출력 결과를 통해 그룹을 연결하여 보여준다.
    printf("%0.14lld",...);
    //            
    
    #include
    using namespace std;
    typedef long long ll;
    #define mod 100000000000000
    ll A[10000000];
    int main(){
         
        ll n;
        scanf("%lld",&n);
        A[0]=1;
        ll i,j,l=0;
        for(i=1;i<=n;i++){
         
            ll c=0;
            for(j=0;j<=l;j++){
         
                ll t=A[j]*i+c;
                A[j]=t%mod;
                c=t/mod;
            }
            if(c!=0){
         
                A[++l]=c;
            }
        }
        printf("%lld",A[l]);
        for(int i=l-1;i>=0;i--){
         
            printf("%0.14lld
    "
    ,A[i]); } //system("pause"); return 0; }

    N의 곱하기 길이


    대수의 성질에 따라: log10(x)log10(x)log10(x), xxx가 10이면 결과는 1, 1위;100위, 결과는 2, 3위... 우리는 총괄할 수 있다, n!n! n!몇 분이면 l o g 10 (n!)log10(n!) log10(n!)의 결과 더하기 1.데이터 범위는 106 10^6 106으로 우리는 선형의 누적법으로 결과를 낼 수 있다.마지막으로 정돈할 때 플로어 함수를 사용했지만 소수점 자릿수가 많을 때 오류가 발생했습니다.강제로 정돈하여 최종적으로 정확한 답안을 얻었다.
    #include
    using namespace std;
    int main(){
         
        double ans=0;
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
         
            ans+=log10(i*1.0);
        }
        cout<<ans<<endl;
        cout<<(long long)(ans)+1<<endl;
        //system("pause");
        return 0;
    }
    

    바둑 이론(세 가지 간단한 바둑 모델)


    Bash 게임


    A, B 두 사람이 한 무더기의 돌을 가지고 모두 n개를 가지는데 매번 [1,k]개를 가지면 누가 먼저 들고 누가 이긴다.번갈아 잡다
    만약 n이 k+1의 배수라면 A가 임의의 값 x를 취하든 B는 k+1-x를 취하면 필승을 보장할 수 있다.같은 이치로 n이 k+1의 배수가 아니라면 첫 번째 단계에서 n%(k+1)를 얻은 다음에 AB가 신분을 바꾸는 것과 같으니 A가 반드시 이길 것이다.
    #include
    using namespace std;
    typedef long long ll;
    ll n,k;
    int t;
    int main(){
         
        cin>>t;
        while(t--){
         
            cin>>n>>k;
            if(n%(k+1)) cout<<"A"<<endl;
            else cout<<"B"<<endl;
        }
        return 0;
    }
    

    Nim 게임


    A, B 두 사람은 n더미의 돌을 들고, 한 무더기의 돌을 [1,∞][1,\infty][1,∞]개씩 들고, 매번 최소한 하나를 들고, 최대 한 무더기를 들고, 가장 먼저 다 잡은 사람이 이긴다.A선수.
    #include
    using namespace std;
    typedef long long ll;
    int n;
    ll a;
    ll ans;
    int main(){
         
        cin>>n;
        for(int i=1;i<=n;i++){
         
            cin>>a;
            ans^=a;
        }
        if(ans) cout<<"A"<<endl;
        else cout<<"B"<<endl;
        //system("pause");
        return 0;
    }
    

    위조프 게임

    좋은 웹페이지 즐겨찾기