2017-10-15 NOIP模拟赛

 Stack

#include<iostream>
#include<cstdio>
#define mod 7
using namespace std;
int f[1010][1010],n;
int main(){
    freopen("stack.in","r",stdin);freopen("stack.out","w",stdout);
    scanf("%d",&n);
    for(int i=0;i<=n;i++)
        for(int j=0;j<=i;j++){
            if(j)f[i][j]=f[i-1][j]+f[i][j-1];
            else f[i][j]=1;
            while(f[i][j]>=mod)f[i][j]-=mod;
        }
    printf("%d",f[n][n]);
    return 0;
}
100分 卡特兰数求第n项取模

Cube

/*
    记录每个点下面有多少元素top[i],他所在并查集的大小,每次移动操作就把移动后在上面的那部分中所有的点的top加上它移动到的病茶几的大小,修改复杂度很高,查询是O(1)的
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 30010
using namespace std;
int p,fa[maxn],sz[maxn],top[maxn];
char ch[5];
int find(int x){
    if(fa[x]==x)return fa[x];
    return fa[x]=find(fa[x]);
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("cube.in","r",stdin);freopen("cube.out","w",stdout);
    scanf("%d",&p);
    int n=0;
    for(int i=1;i<=30000;i++)fa[i]=i,sz[i]=1;
    while(p--){
        scanf("%s",ch);
        int x,y;
        if(ch[0]=='M'){
            scanf("%d%d",&x,&y);
            n=max(n,max(x,y));
            int f1=find(x),f2=find(y);
            if(f1!=f2){
                for(int i=1;i<=n;i++){
                    if(find(i)==f1){
                        top[i]+=sz[f2];
                    }
                }
                fa[f1]=f2;
                sz[f2]+=sz[f1];
                sz[f1]=0;
            }
            
        }
        else{
            scanf("%d",&x);
            n=max(n,x);
            printf("%d
",top[x]);
        }
    }
}
70分 暴力并查集
#include<iostream>
#include<cstdio>
#define maxn 30010
using namespace std;
int p,cnt[maxn],sum[maxn],fa[maxn];
char s[4];
int find(int x){
    if(x==fa[x])return fa[x];
    int f=fa[x];
    fa[x]=find(fa[x]);
    cnt[x]+=cnt[f];
    return fa[x];
}
void merge(int x,int y){
    fa[y]=x;
    cnt[y]+=sum[x];
    sum[x]+=sum[y];
    sum[y]=0;
}
int main(){
    freopen("cube.in","r",stdin);freopen("cube.out","w",stdout);
    for(int i=1;i<=30000;i++)fa[i]=i,sum[i]=1;
    scanf("%d",&p);
    while(p--){
        scanf("%s",s);
        int x,y;
        if(s[0]=='M'){
            scanf("%d%d",&x,&y);
            merge(find(x),find(y));
        }
        else {
            scanf("%d",&x);
            printf("%d
",sum[find(x)]-cnt[x]-1);
        }
    }
}
100分 带权并查集

Zuma

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<queue>
using namespace std;
map<string,bool>vis;
string s,snow;
struct node{
    string s;
    int step;
}cur,nxt;
queue<node>q;
void down(){
    string pre=snow;
    snow="";
    for(int i=0;i<pre.length();){
        while(pre[i]=='2'&&i<pre.length())i++;
        snow=snow+pre[i];i++;
    }
}
void updata(){
    string pre=snow;
    bool flag=0;
    for(int i=0;i<pre.length();i++){
        if(pre[i]==pre[i-1]&&pre[i]==pre[i+1])flag=1,snow[i]=snow[i-1]=snow[i+1]='2';
    }
    if(flag){
        down();
        updata();
    }
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("zuma.in","r",stdin);freopen("zuma.out","w",stdout);
    cin>>s;
    vis[s]=1;
    cur.s=s;cur.step=0;
    //cout<<s<<endl;
    bool flag=0;
    int n1=0,n0=0;
    for(int i=1;i<s.length();i++){
        if(s[i]==s[i-1]){
            flag=1;break;
        }
        if(s[i]=='0')n0++;
        if(s[i]=='1')n1++;
    }
    if(flag==0){
        int ans=0;
        if(s[0]=='0')n0++;
        if(s[0]=='1')n1++;
        if(n1%2==0&&n0%2==0&&n1==n0){
            ans=2+(n1/2)+((n0-2)/2)+2;
            printf("%d",ans);
            return 0;
        }
        if(n1%2==1&&n0%2==1&&n1==n0){
            ans=4+((n1-1)/2)+((n0-1)/2);
            printf("%d",ans);
            return 0;
        }
        if(n1<n0)swap(n1,n0);
        if(n1%2==1&&n0==n1-1){
            ans=2+((n1-1)/2)+(n0/2);
            printf("%d",ans);
            return 0;
        }
        if(n1%2==0&&n0==n1-1){
            ans=2+(n1/2)+((n0-1)/2);
            printf("%d",ans);
            return 0;
        }
    }
    q.push(cur);
    while(!q.empty()){
        cur=q.front();q.pop();
        int len=cur.s.length();
        //cout<<cur.s<<endl;
        if(len==0){printf("%d",cur.step);return 0;}
        for(int i=0;i<=len;i++){//在第i个前面插 
            snow="";
            snow=snow+cur.s.substr(0,max(0,i));
            snow=snow+"0";
            snow=snow+cur.s.substr(i,len-i);
            string now=snow;
            updata();
            if(!vis[snow]){
                vis[snow]=1;
                nxt.s=snow;nxt.step=cur.step+1;
                q.push(nxt);
                if(nxt.s.length()==1&&nxt.s[0]!='0'&&nxt.s[0]!='1'){printf("%d",nxt.step);return 0;}
            }
            //cout<<snow<<endl;
            
            snow=now;
            snow[i]='1';
            updata();
            if(!vis[snow]){
                vis[snow]=1;
                nxt.s=snow;nxt.step=cur.step+1;
                q.push(nxt);
                if(nxt.s.length()==1&&nxt.s[0]!='0'&&nxt.s[0]!='1'){printf("%d",nxt.step);return 0;}
            }
            //cout<<snow<<endl;
        }
    }
    fclose(stdin);fclose(stdout);
    return 0;
}
65分 宽搜
/*
    区间dp,情况有些多需要讨论
    首先连续相同的颜色为了方便要合并,记录每个块的颜色,就可以dp了
    dp[l][r]表示合并这段区间的最小步数,分几种情况
    这段区间是奇数(为了避免区间长度为2的情况)
    1. color[l]==color[r] && tot[l]+tot[r]==2  --> dp[l][r] 可从 dp[l+1][r-1]+1 转移过来。
    2. color[l]==color[r] && tot[l]+tot[r]>2   --> dp[l][r] 可从 dp[l+1][r-1] 转移过来。
    3. color[l]==color[k]==color[r](k∈(l,r) && [l,k],[k,r] 为奇数)  -->可从dp[l+1][k-1]+dp[k+1][r-1]转移过来。
    这段区间是偶数
    普通的转移 dp[l][r] =min(dp[l][r] , dp[l][k]+dp[k+1][r]);
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 257
using namespace std;
int dp[maxn][maxn],col[maxn],a[maxn];
char s[maxn];
int n,m,ans;
int main(){
    freopen("zuma.in","r",stdin);freopen("zuma.out","w",stdout);
    scanf("%s",s);n=strlen(s);
    a[1]=1;m=1;
    for(int i=1;i<n;i++){
        if(s[i]==s[i-1]){
            col[m]=s[i]-'0';
            a[m]++;
        }
        else {
            a[++m]=1;
            col[m]=s[i]-'0';
        }
    }
    for(int len=0;len<=m;len++){
        for(int i=1;i<=m;i++){
            int j=i+len;
            if(j>=1&&j<=m){
                dp[i][j]=2*n;
                if(len==0)dp[i][j]=3-a[i];
                else {
                    for(int k=i;k<j;k++)
                        dp[i][j]=min(dp[i][k]+dp[k+1][j],dp[i][j]);
                    if((j-i)%2==0){
                        if(a[i]+a[j]==2){
                            if(col[i]==col[j])
                                dp[i][j]=min(dp[i][j],dp[i+1][j-1]+1);
                        }
                        else
                            if(col[i]==col[j])
                                dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
                        if(a[i]+a[j]<4)
                            for(int k=i+2;k<j;k+=2)
                                if(a[k]==1)dp[i][j]=min(dp[i+1][k-1]+dp[k+1][j-1],dp[i][j]);
                    }
                }
            }
        }
    }
    printf("%d
",dp[1][m]);
    return 0;
}
100分 区间dp
原文地址:https://www.cnblogs.com/thmyl/p/7670269.html