NOIP2015 improve group problem solution

\ (D1T1 \) magical magic square \ ((OK) \)

\ (D1T2 \) information transfer \ ((OK) \)

\ (D1T3 \) Landlords \ ((OK) \)

\ (D1T4 \) Landlords enhanced version \ ((OK) \)

\ (D2T1 \) jump stone \ ((OK) \)

\ (D2T2 \) substring \ ((the OK) \)

\ (D2T3 \) transport plan

Only a question of cancer, \ (NOIP \) , there will be an annual one big data structure that discouraging \ (? \)

\ (D1T1 \) opened a two-dimensional array from the first number to start the simulation meaning of the questions just fine.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
int a[40][40];
int main(){
    int n=read(),i=1,j=n/2+1;a[i][j]=1;
    for(int now=2;now<=n*n;++now){
        if(i==1&&j!=n){
            a[n][j+1]=now;
            i=n;j=j+1;continue;
        }
        if(j==n&&i!=1){
            a[i-1][1]=now;
            i=i-1;j=1;continue;
        }
        if(i==1&&j==n){
            a[2][j]=now;
            i=2;j=n;continue;
        }
        if(i!=1&&j!=n){
            if(!a[i-1][j+1]){
                a[i-1][j+1]=now;
                i=i-1;j=j+1;
            }
            else{
                a[i+1][j]=now;
                i=i+1;j=j;
            }
        }
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j)cout<<a[i][j]<<" ";
        cout<<endl;
    }
    return 0;
}

\ (D1T2 \) all know the answer to that length figure smallest ring, then how to find the smallest ring figure it? Note that this is a directed graph, not that \ (tarjan \) template title yet? Then there \ ( dfs \) other good practices, disjoint-set and so on, I will not.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=200005;
int a[N];
int tim,top,num,dfn[N],low[N],st[N],color[N],size[N];
inline void tarjan(int u){
    dfn[u]=low[u]=++tim;st[++top]=u;
    int v=a[u];
    if(!dfn[v]){
        tarjan(v);
        low[u]=min(low[u],low[v]);
    }
    else if(!color[v]){
        low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        color[u]=++num;
        ++size[num];
        while(st[top]!=u){
            color[st[top]]=num;
            ++size[num];--top;
        }
        --top;
    }
}
int main(){
    int n=read(),ans=n;
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i);
    for(int i=1;i<=num;++i)if(size[i]>1)ans=min(ans,size[i]);
//注意不要把大小为1的强连通分量(环)算进去了
    printf("%d\n",ans);
    return 0;
}

\ (D1T3 \) This question I probably do two or three hours, the pit place in this discussion, this question of the district (that is not a straight long as possible \ (!!! \) ). Then a little attention about the search (the cards) order. Finally when you put all what straight single, double straight, three of the four were out over the rest of each card must either 1 or 2 one, then count the number of accumulated into direct answer, but do not go on a search again each time, will \ (T \) fly.

After writing this question again enhanced version of the code directly submitted data, we found only wrong two points, then the next data down (Ah, in the face of data programming), A point is found two bombs once finished out (ie, a bomb with two pair), there is a point forgotten, in short, is a program I wrote before default with a card with a different type of card, a little change a place just fine.

Placed directly enhanced version \ (AC \) Code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
int n,ans,sum[20];
inline int check3(){
    for(int i=3;i<=13;++i)
        if(sum[i]>=3&&sum[i+1]>=3)return i;
    return 0;
}
inline int check2(){
    for(int i=3;i<=12;++i)
        if(sum[i]>=2&&sum[i+1]>=2&&sum[i+2]>=2)return i;
    return 0;
}
inline int check_sz(){
    for(int i=3;i<=10;++i)
        if(sum[i]&&sum[i+1]&&sum[i+2]&&sum[i+3]&&sum[i+4])return i;
    return 0;
}
inline int check_zd(){
    for(int i=1;i<=14;++i)
        if(sum[i]==4)return i;
    return 0;
}
inline int check_san(){
    for(int i=1;i<=14;++i)
        if(sum[i]>=3)return i;
    return 0;
}
inline void dfs(int now){
    if(now>=ans)return;
    int sz=check_sz();
    if(sz){//单顺子
        int i=sz,cnt=0;
        for(;i<=15;++i){
            if(sum[i]){
                ++cnt;
                if(cnt>=5){//不是越长越好,所以每种合法长度都要搜
                    for(int j=sz;j<=i;++j)--sum[j];
                    dfs(now+1);
                    for(int j=sz;j<=i;++j)++sum[j];
                }
            }
            else break;
        }
    }
    int y=check2();
    if(y){//双顺子
        int i=y,cnt=0;
        for(;i<=15;++i){
            if(sum[i]>=2)sum[i]-=2,cnt+=2;
            else break;
        }
        dfs(now+1);
        for(int j=y;j<i;++j)sum[j]+=2;
    }
    int x=check3();
    if(x){//三顺子(不是飞机,不能带牌)
        int i=x,cnt=0;
        for(;i<=15;++i){
            if(sum[i]>=3)sum[i]-=3,cnt+=3;
            else break;
        }
        dfs(now+1);
        for(int j=x;j<i;++j)sum[j]+=3;
    }
    int san=check_san();
    if(san){//三个带一个或一对,一对不能是王炸
        sum[san]-=3;
        for(int i=2;i<=14;++i){
            if(sum[i]>=2){
                sum[i]-=2;
                dfs(now+1);
                sum[i]+=2;
            }
        }
        for(int i=0;i<=14;++i){
            if(sum[i]>=1){
                sum[i]-=1;
                dfs(now+1);
                sum[i]+=1;
            }
        }
        sum[san]+=3;
    }
    int zd=check_zd();
    if(zd){//四个带两个或两对,同样一对不能是王炸
        sum[zd]-=3;//四个可以先做3个的带
        for(int i=2;i<=14;++i){
            if(sum[i]>=2){
                sum[i]-=2;
                dfs(now+1);
                sum[i]+=2;
            }
        }
        for(int i=0;i<=14;++i){
            if(sum[i]>=1&&i!=zd){
                sum[i]-=1;
                dfs(now+1);
                sum[i]+=1;
            }
        }
        sum[zd]+=3;
        sum[zd]-=4;//再来搜索做4个的带
        for(int i=2;i<=14;++i){
            if(sum[i]>=2){
                sum[i]-=2;
                for(int j=i;j<=14;++j){
                    if(sum[j]>=2){
                        sum[j]-=2;
                        dfs(now+1);
                        sum[j]+=2;
                    }
                }
                sum[i]+=2;
            }
        }
        for(int i=0;i<=14;++i){
            if(sum[i]>=1){
                --sum[i];
                for(int j=i;j<=14;++j){
                    if(sum[j]>=1){
                        --sum[j];
                        dfs(now+1);
                        ++sum[j];
                    }
                }
                ++sum[i];
            }
        }
        sum[zd]+=4;
    }
    for(int i=0;i<=14;++i)if(sum[i])++now;
    ans=min(ans,now);
}
int main(){
    int T=read(),n=read();
    while(T--){
        for(int i=0;i<=15;++i)sum[i]=0;
        for(int i=1;i<=n;++i){
            int x=read(),y=read();
            if(x==1)x=14;++sum[x];
        }
        ans=n;dfs(0);printf("%d\n",ans);
    }
    return 0;
}

\ (D2T1 \) Well, that is half the answer to the question of the template. The minimum jump distance of half the maximum value \ (mid \) , the distance if there are two stone less than \ (mid \) , which then put it back stones removed (obviously to the latter than to the foregoing superior).

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=50005;
int L,n,m,a[N],b[N];
inline bool check(int mid){
    for(int i=1;i<=n;++i)b[i]=a[i];b[n+1]=L;
    int cnt=0;
    for(int i=1;i<=n+1;++i){
        if(b[i]-b[i-1]<mid){
            ++cnt;b[i]=b[i-1];
        }
    }
    return cnt<=m;
}
int main(){
    L=read(),n=read(),m=read();
    for(int i=1;i<=n;++i)a[i]=read();
    int l=0,r=L,ans,mid;
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid))ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

\ (D2T2 \) a good \ (dp \) , made himself afternoon will not,After reading solution to a problem suddenlyLet \ (f [i] [j ] [k] [0/1] \) represents the currently considered the \ (A \) string of \ (I \) characters matching the \ (B \) string the first \ (j \) characters, which \ (j \) character is divided into separate \ (k \) section elected, current \ (i \) characters selected / non-selected number scheme.

\ (F [I] [J] [K] [0] = F [I-. 1] [J] [K] [0] + F [I-. 1] [J] [K] [. 1] \) , current \ (i \) character is not selected, then whatever lies ahead, your first \ (i-1 \) characters can be selected or not selected transfer over.

When the (A [i] = B [ j] \) \ time, \ (F [I] [J] [K] [. 1] = F [I-. 1] [J-. 1] [K-. 1] [0 ] + F [I-. 1] [J-. 1] [K-. 1] [. 1] + F [I-. 1] [J-. 1] [K] [. 1] \) , if selected current \ (I \ ) character, and this character just to match, if this character alone into segments, then whatever lies ahead, your first \ (i-1 \) characters can be selected or not selected transferred from (ie \ (f [i-1 ] [. 1-J] [K-. 1] [0] + F [. 1-I] [J-. 1] [-K. 1] [. 1] \) ), if the current character with the character followed by a segment into, Required then the above that character (i.e. \ (F [. 1-I] [. 1-J] [K] [. 1] \) ).

When \ (A [i] \) is not equal to \ (B [j] \) when, \ (F [I] [J] [K] [. 1] = 0. \)

Then directly open the array \ (1000 * 1000 * 200 * 2 \) is less than the open, in accordance with routine ( \ (I \) only from (i-1 \) \ transfer over time), a first dimension either rolling or roll out.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int mod=1e9+7;
const int N=1005;
int n,m,K;ll f[2][N][205][2];
char s1[N],s2[N];
int main(){
    n=read();m=read();K=read();
    scanf("%s%s",s1+1,s2+1);
    f[0][0][0][0]=1;
    for(int i=1;i<=n;++i){
        for(int j=0;j<=min(i,m);++j){
            for(int k=0;k<=min(j,K);++k){
                f[i&1][j][k][0]=(f[(i-1)&1][j][k][0]+f[(i-1)&1][j][k][1])%mod;
                if(s1[i]==s2[j])f[i&1][j][k][1]=(f[(i-1)&1][j-1][k][1]+f[(i-1)&1][j-1][k-1][0]+f[(i-1)&1][j-1][k-1][1])%mod;
                else f[i&1][j][k][1]=0;
            }       
        }
    }
    printf("%lld\n",(f[n&1][m][K][0]+f[n&1][m][K][1])%mod);
    return 0;
}

Guess you like

Origin www.cnblogs.com/PPXppx/p/11779233.html
Recommended