NOIP 2015 题解

来源:互联网 发布:像素人物制作软件 编辑:程序博客网 时间:2024/05/19 04:26

终于搞完了!!!!!
dalao们都说水,但蒟蒻表示挺难的;
有件事很开心;
其中四道题是自己独立AC的;
一道想到正解(Day 2 T3),但不会卡常;
至于还有一道……一点思路也没有(Day 2 T2);

Day 1

T1:

题目:
https://www.luogu.org/problem/show?pid=2615

模拟,日常签到题,注意坐标具有传递性;

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;int ma[2001][2001],n,tot=1;void solve(){    scanf("%d",&n);    ma[1][n/2+1]=tot;    int x=1,y=n/2+1;    while(tot<n*n)    {        tot++;        if(x==1 && y!=n) x=n,y++;        else if(x!=1 && y==n) y=1,x--;        else if(x==1 && y==n) x++;        else if(x!=1 && y!=n)        {            if(!ma[x-1][y+1]) x--,y++;            else x++;        }        ma[x][y]=tot;    }    for(int i=1;i<=n;i++)    {        for(int j=1;j<=n;j++) cout<<ma[i][j]<<" ";        cout<<endl;    }}int main(){    solve();    return 0;}

T2:

题目:
https://www.luogu.org/problem/show?pid=2661
tarjan或dfs;

比较裸的求最小环;

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<stack>using namespace std;stack<int>s;const int MAXN=200001;int dfn[MAXN],low[MAXN],fst[MAXN],nxt[MAXN],scc[MAXN];int n,tot,tim,cnt,f,ans=324252;struct hh{    int from,to;}map[MAXN];void build(int f,int t){    tot++;    map[tot]=(hh){f,t};    nxt[tot]=fst[f];    fst[f]=tot;    return;}void tarjan(int x){    low[x]=dfn[x]=++tim;    s.push(x);    for(int i=fst[x];i!=-1;i=nxt[i])    {        int v=map[i].to;        if(!dfn[v])        {            tarjan(v);            low[x]=min(low[x],low[v]);        }        else if(!scc[v]) low[x]=min(low[x],dfn[v]);    }    if(dfn[x]==low[x])    {        cnt++;        int num=0;        while(true)        {            int u=s.top();            s.pop();            num++,scc[x]=cnt;            if(u==x)            {                if(num>1) ans=min(num,ans);                break;            }        }    }    return;}void solve(){    memset(fst,-1,sizeof(fst));    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d",&f);        build(i,f);    }    for(int i=1;i<=n;i++)        if(!dfn[i]) tarjan(i);    cout<<ans;    return;}int main(){    solve();    return 0;}

T3:
题目:
https://www.luogu.org/problem/show?pid=2668

注意答案的更新;
挺简单的一道题,但是细节处理较多;

题解:http://blog.csdn.net/qq_36312502/article/details/77970178;

爆搜;

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int t,n,cnt[10001],ans,num;void init(){    memset(cnt,0,sizeof(cnt));    ans=n;    return;}int cnt1,cnt2,cnt3,cnt4,cnt5;void dfs(int x){    cnt1=cnt2=cnt3=cnt4=cnt5=0;    for(int i=1;i<=14;i++)    {        if(cnt[i]==1) cnt1++;        else if(cnt[i]==2) cnt2++;    }    for(int i=1;i<=14;i++)//三带一 三带二     {        if(cnt[i]==3)        {            cnt3++;            if(cnt1>=1) cnt1--;            else if(cnt2>=1) cnt2--;        }    }    for(int i=1;i<=14;i++) //四带二     {        if(cnt[i]==4)        {            cnt4++;            if(cnt1>=2) cnt1-=2;            else if(cnt2>=2) cnt2-=2;            else if(cnt2>=1) cnt2--;//四带一个对子也可以;        }    }    ans=min(ans,x+cnt1+cnt2+cnt3+cnt4);    for(int i=1;i<=8;i++) //单顺子     {        int j;        for(j=i;j<=12;j++)        {            if(cnt[j]<1) break;            cnt[j]--;            if(j-i>=4) dfs(x+1);        }        for(int k=i;k<=j-1;k++) cnt[k]++;    }    for(int i=1;i<=10;i++) // 双顺子     {        int j;        for(j=i;j<=12;j++)        {            if(cnt[j]<2) break;            cnt[j]-=2;            if(j-i>=2) dfs(x+1);         }        for(int k=i;k<=j-1;k++) cnt[k]+=2;    }    for(int i=1;i<=11;i++) // 三顺子     {        int j;        for(j=i;j<=12;j++)        {            if(cnt[j]<3) break;             cnt[j]-=3;            if(j-i>=1) dfs(x+1);         }        for(int k=i;k<=j-1;k++) cnt[k]+=3;    }    return;}void solve(){    init();    int x,y;    for(int i=1;i<=n;i++)    {        scanf("%d%d",&x,&y);        if(x==0) cnt[14]++;        else if(x==1) cnt[12]++;        else if(x==2) cnt[13]++;        else cnt[x-2]++;    }      dfs(0);    cout<<ans<<endl;}int main(){    scanf("%d%d",&t,&n);    int hh=t;    while(hh--) solve();    return 0;}

Day 2

T1:

题目:
https://www.luogu.org/problem/show?pid=2678

二分;

题解:
http://blog.csdn.net/qq_36312502/article/details/77869900

#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>using namespace std;int r,l=1,L,n,m,ans,last;int a[100001];bool check(int x){    int ans=0,last=0;    for(int i=1;i<=n+1;i++)    {        if(a[i]-last<x) ans++;        else last=a[i];    }    if(ans>m) return 1;    else return 0;}void solve(){    cin>>L>>n>>m;    for(int i=1;i<=n;i++) scanf("%d",&a[i]);    r=a[n+1]=L;    while(r-l>1)    {        int mid=(l+r)>>1;        if(check(mid)) r=mid;        else l=mid;    }    if(!check(r)) l=r;    cout<<l;}int main(){    solve();    return 0;}

T2:

题目:
https://www.luogu.org/problem/show?pid=2679

DP,难;
题解:
http://blog.csdn.net/qq_36312502/article/details/78127290

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int mod=1000000007;int dp[3][301][301][3],cnt,now,pre=1,n,m,t;char s1[1021],s2[1021];void solve(){    cin>>n>>m>>t;    scanf("%s%s",s1+1,s2+1);    for(int i=1;i<=n;i++)    {        swap(now,pre);        dp[now][1][1][0]=cnt;        if(s1[i]==s2[1]) dp[now][1][1][1]=1,cnt++;        for(int j=2;j<=m;j++)        {            for(int k=1;k<=t;k++)            {                if(s1[i]==s2[j])                dp[now][j][k][1]=((dp[pre][j-1][k-1][0]+dp[pre][j-1][k-1][1])%mod+dp[pre][j-1][k][1])%mod;                dp[now][j][k][0]=(dp[pre][j][k][0]+dp[pre][j][k][1])%mod;            }        }        for(int j=1;j<=m;j++)            for(int k=1;k<=t;k++)                 dp[pre][j][k][1]=dp[pre][j][k][0]=0;    }    cout<<(dp[now][m][t][1]+dp[now][m][t][0])%mod;    return;}int main(){    solve();    return 0;}

T3:

题目:
https://www.luogu.org/problem/show?pid=2680

lca+树上差分+二分;

题解:
http://blog.csdn.net/qq_36312502/article/details/78121945

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int MAXN=600008;int fst[MAXN],nxt[MAXN],num[MAXN],tmp[MAXN],dis[MAXN];int deep[MAXN],top[MAXN],sz[MAXN],fa[MAXN],son[MAXN],dfn[MAXN];int tot,n,m,l=-1,r,totp;struct hh {int from,to,cost;}ss[MAXN];struct edge {int from,to,lca,dis;}ma[MAXN];void build(int f,int t,int c){    tot++;    ss[tot]=(hh){f,t,c};    nxt[tot]=fst[f];    fst[f]=tot;    return;}void dfs1(int x,int f,int c){    dfn[++totp]=x;    fa[x]=f,deep[x]=deep[f]+1,sz[x]=1,dis[x]=c;    for(int i=fst[x];i;i=nxt[i])    {        int v=ss[i].to;        if(v==f) continue;        num[v]=ss[i].cost;        dfs1(v,x,c+ss[i].cost),sz[x]+=sz[v];        if(!son[x] || sz[son[x]]<sz[v]) son[x]=v;    }    return;}void dfs2(int x,int st){    top[x]=st;    if(!son[x]) return;    dfs2(son[x],st);    for(int i=fst[x];i;i=nxt[i])    {        int v=ss[i].to;        if(v==fa[x] || v==son[x]) continue;        dfs2(v,v);    }    return;}int lca(int x,int y){    int fx=top[x],fy=top[y];    while(fx!=fy)    {        if(deep[fx]<deep[fy]) swap(fx,fy),swap(x,y);        x=fa[fx],fx=top[x];    }    return deep[x]<deep[y]?x:y;}bool check(int ans){    int lim=-1,cnt=0;    memset(tmp,0,sizeof(tmp));    for(int i=1;i<=m;i++)    {        if(ma[i].dis>ans)        {            tmp[ma[i].from]++,tmp[ma[i].to]++;            tmp[ma[i].lca]-=2;            lim=max(lim,ma[i].dis-ans);            cnt++;        }    }    if(!cnt) return true;    for(int i=n;i>=1;i--) tmp[fa[dfn[i]]]+=tmp[dfn[i]];    for(int i=2;i<=n;i++)        if(num[i]>=lim && tmp[i]==cnt) return true;    return false;}void solve(){    int x,y,z;    scanf("%d%d",&n,&m);    for(int i=1;i<n;i++)    {        scanf("%d%d%d",&x,&y,&z);        build(x,y,z),build(y,x,z);        r+=z;    }    dfs1(1,0,0),dfs2(1,1);    for(int i=1;i<=m;i++)    {        scanf("%d%d",&x,&y);        ma[i]=(edge){x,y,lca(x,y),dis[x]+dis[y]-2*dis[lca(x,y)]};    }    while(r-l>1)    {        int mid=(l+r)>>1;        if(check(mid)) r=mid;        else l=mid;    }    cout<<r;    return;}int main(){    solve();    return 0;}
原创粉丝点击