【NOIP2015】提高组

因为一些事情补了三天终于补完辣><



DAY1

T1神奇的幻方

题目链接

超级水的模拟题......一次过

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int map[40][40]={0};
int main()
{
    int n,head[2];
    scanf("%d",&n);
    map[1][n/2+1]=1;
    head[0]=1;head[1]=n/2+1;
    for(int i=2;i<=n*n;i++)
    {
        if(head[0]==1&&head[1]!=n){map[n][head[1]+1]=i;head[0]=n;head[1]+=1;continue;}
        if(head[0]!=1&&head[1]==n){map[head[0]-1][1]=i;head[0]-=1;head[1]=1;continue;}
        if(head[0]==1&&head[1]==n){map[head[0]+1][head[1]]=i;head[0]+=1;continue;}
        if(!map[head[0]-1][head[1]+1]){map[head[0]-1][head[1]+1]=i;head[0]-=1;head[1]+=1;continue;}
        map[head[0]+1][head[1]]=i;head[0]+=1;
    }
    for(int j=1;j<=n;j++)
    {
        for(int i=1;i<=n;i++)
            printf("%d ",map[j][i]);
        printf("\n");
    }
    return 0;
}

Day1 T1

T2信息传递

题目链接

挺巧妙的一个dfs,原理就是同一个环里每个点走一圈回到本身的距离相等,再注意判断是否已经在已知环里即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M=2e5+10;
using namespace std;
int n,a[M],len,t=M,huan[M],h=0,now=0;
int ok[M];
int read()
{
    int f=1,ans=0;char c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+c-48;c=getchar();}
    return ans*f;
}
void dfs(int x)
{
    ok[x]=now;
    huan[x]=h;
    if(ok[a[x]]){
        if(huan[a[x]]==h)t=min(t,now-ok[a[x]]+1);
        return;
    }
    now++;
    dfs(a[x]);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)
    {
        if(!ok[i]){now++;h++;dfs(i);}
    }
    printf("%d",t);
    return 0;
}

Day1 T2

T3斗地主

题目链接

这一年的NOIP提高最后补完的一道题...之前一直不敢写,但是zsn写完后说其实没有想象中的那么难,所以我的代码基本也是她的思路吧(orz zsnuo),挺好理解的dfs,就是自己想不到:(

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int sum[15],tot,a[5];
int read()
{
    int ans=0,f=1;char c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+c-48;c=getchar();}
    return ans*f;
}
int da()
{
    bool f=0;
    if(sum[0]==2)f=true;
    memset(a,0,sizeof(a));
    for(int i=0;i<=13;i++)a[sum[i]]++;
    int num=0;
    while(a[4]&&a[2]>=2){f=false;a[4]--;a[2]-=2;num++;}
    while(a[4]&&a[1]>=2){a[4]--;a[1]-=2;num++;}
    while(a[4]&&a[2]){f=false;a[4]--;a[2]--;num++;}
    if(f)a[2]--,num++;
    while(a[3]&&a[2]){a[3]--;a[2]--;num++;}
    while(a[3]&&a[1]){a[3]--;a[1]--;num++;}
    return num+a[1]+a[2]+a[3]+a[4];
}
void dfs(int st)
{
    if(st>=tot)return;
    int t=da();
    tot=min(tot,st+t);
    for(int i=2;i<=13;i++){
        int ne=i;
        while(sum[ne]>=3)ne++;
        if(ne-i>=2){
            for(int j=i+1;j<=ne-1;j++){
                for(int k=i;k<=j;k++)sum[k]-=3;
                dfs(st+1);
                for(int k=i;k<=j;k++)sum[k]+=3;
            }
        }
    }
    for(int i=2;i<=13;i++){
        int ne=i;
        while(sum[ne]>=2)ne++;
        if(ne-i>=3){
            for(int j=i+2;j<=ne-1;j++){
                for(int k=i;k<=j;k++)sum[k]-=2;
                dfs(st+1);
                for(int k=i;k<=j;k++)sum[k]+=2;
            }
        }
    }
    for(int i=2;i<=13;i++){
        int ne=i;
        while(sum[ne])ne++;
        if(ne-i>=5){
            for(int j=i+4;j<=ne-1;j++){
                for(int k=i;k<=j;k++)sum[k]--;
                dfs(st+1);
                for(int k=i;k<=j;k++)sum[k]++;
            }
        }
    }
}
int main()
{
    int tt,n,ai,bi;
    tt=read();n=read();
    while(tt--){
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++){
            ai=read();bi=read();
            if(ai==1)sum[13]++;
                else if(ai)sum[ai-1]++;
                    else sum[0]++;
        }
        tot=25;
        dfs(0);
        printf("%d\n",tot);
    }
    return 0;
}

Day1 T3



Day2

T1跳石头

题目链接

这道题直接二分跳跃的最大距离,然后判断能否通过移走不超过m块石头来使得最大跳跃距离不小于当前答案。当然二分的细节需要特别注意。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int a[50008];
int read()
{
    int ans=0,f=1;char c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+c-48;c=getchar();}
    return ans*f;
}
int main()
{
    int n,m,len,i,j,aa;
    len=read();n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    a[0]=0;a[n+1]=len;
    int l=0,r=len;
    while(l<r-1)
    {
        i=0;aa=0;
        int mid=(l+r)>>1;
        while(i<=n)
        {
            j=i+1;
            while(a[j]-a[i]<mid&&j<=n+1)j++;
            aa+=j-i-1;
            i=j;
        }
        if(aa<=m)l=mid;
        else r=mid;
    }
    printf("%d",l);
    return 0;
}

Day2 T1

T2子串

题目链接

感觉自己的dp很弱,可能没法讲得很清楚QAQ,所以还是直接甩别人的题解吧~

然后因为第一维都只和i-1有关,所以直接开成滚动的,每次再^1就不会MLE辣。

#include<cstdio>
#include<cstring>
#include<algorithm>
const int mod=1e9+7;
using namespace std;
char a[1002],b[202];
int f[2][202][202],s[2][202][202];
int main()
{
    int n,m,k,no=1;
    scanf("%d %d %d",&n,&m,&k);
    scanf("%s %s",a+1,b+1);
    f[0][0][0]=1;
    for(int i=1;i<=n;i++){
        f[no][0][0]=1;
        for(int j=1;j<=i&&j<=m;j++){
            for(int kk=1;kk<=k&&kk<=j;kk++){
                if(a[i]==b[j])s[no][j][kk]=(s[no^1][j-1][kk]+f[no^1][j-1][kk-1])%mod;
                else s[no][j][kk]=0;
                f[no][j][kk]=(f[no^1][j][kk]+s[no][j][kk])%mod;
            }
        }
        no^=1;
    }
    printf("%d",f[no^1][m][k]);
    return 0;
}

Day2 T2

T3运输计划

题目链接

没错最后一题日常看Zsnuo的题解......(Zsnuo dalao太强啦><)二分答案+lca,看完基本就懂啦!

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e5+5;
struct point{
    int next,to,w;
}e[N*2];
int n,m,ai,bi,ci,tot=0;
int deep[N],gr[N][22],dis[N][22];
int st[N],ed[N],fa[N],dist[N],first[N],sum[N];
bool ok[N];
int read()
{
    int f=1,ans=0;char c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+c-48;c=getchar();}
    return ans*f;
}
void ins(int u,int v,int wi)
{
    tot++;e[tot].next=first[u];e[tot].to=v;first[u]=tot;e[tot].w=wi;
    tot++;e[tot].next=first[v];e[tot].to=u;first[v]=tot;e[tot].w=wi;
}
void dfs(int x)
{
    ok[x]=1;
    for(int i=1;(1<<i)<=deep[x];i++){
        gr[x][i]=gr[gr[x][i-1]][i-1];
        dis[x][i]=dis[x][i-1]+dis[gr[x][i-1]][i-1];
    }
    for(int i=first[x];i;i=e[i].next){
        int p=e[i].to;
        if(ok[p])continue;
        gr[p][0]=x;
        deep[p]=deep[x]+1;
        dis[p][0]=e[i].w;
        dfs(p);
    }
}
int lca(int x,int y,int num)
{
    if(deep[x]>deep[y])swap(x,y);
    int d=deep[y]-deep[x];
    for(int i=0;(1<<i)<=d;i++)
        if((1<<i)&d){
            dist[num]+=dis[y][i];
            y=gr[y][i];
        }
    if(x==y)return x;
    for(int i=20;i>=0;i--){
        if((1<<i)<=deep[x]&&gr[x][i]!=gr[y][i]){
            dist[num]+=dis[x][i]+dis[y][i];
            x=gr[x][i];y=gr[y][i];
        }
    }
    dist[num]+=dis[x][0]+dis[y][0];
    return gr[x][0];
}
void add(int x)
{
    for(int i=first[x];i;i=e[i].next){
        if(e[i].to==gr[x][0])continue;
        add(e[i].to);
        sum[x]+=sum[e[i].to];
    }
}
bool check(int x)
{
    int num=0,mx=0;
    for(int i=1;i<=n;i++)sum[i]=0;
    for(int i=1;i<=m;i++)
    if(dist[i]>x){
        num++;mx=max(mx,dist[i]-x);
        sum[st[i]]++;sum[ed[i]]++;sum[fa[i]]-=2;
    }
    add(1);
    for(int i=1;i<=n;i++)
        if(sum[i]==num&&mx<=dis[i][0])return 1;
    return 0;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n-1;i++){
        ai=read();bi=read();ci=read();
        ins(ai,bi,ci);
    }
    dfs(1);
    for(int i=1;i<=m;i++){
        st[i]=read();ed[i]=read();
        fa[i]=lca(st[i],ed[i],i);
    }
    int L=0,R=0;
    for(int i=1;i<=m;i++)R=max(R,dist[i]);
    while(L<=R){
        int mid=(L+R)>>1;
        if(check(mid))R=mid-1;
        else L=mid+1;
    }
    printf("%d",L);
    return 0;
}

Day2 T3

时间: 2024-11-10 01:31:48

【NOIP2015】提高组的相关文章

[NOIP2015] 提高组 洛谷P2615 神奇的幻方

题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将K填在(K−1)

洛谷-神奇的幻方-NOIP2015提高组复赛

题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将K填在(K−1)

刷题总结——子串(NOIP2015提高组)

题目: 题目背景 NOIP2015 提高组 Day2 T2 题目描述 有两个仅包含小写英文字母的字符串 A 和 B .现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出的位置不同也认为是不同的方案. 输入格式 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k ,每两个整数之间用一个空格隔

Noip2015 提高组 Day1

T1神奇的幻方 题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将

[NOIP2015] 提高组 洛谷P2678 跳石头

题目背景 一年一度的“跳石头”比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N 块岩石(不含起点和终 点的岩石).在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达 终点. 为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳 跃距离尽可能长.由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能 移走起点和终点的岩石). 输入输出格式 输入格式

[NOIP2015] 提高组 洛谷P2679 子串

题目背景 无 题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案. 输入输出格式 输入格式: 输入文件名为 substring.in. 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问 题描述中所提到的 k,每两个整数之

[NOIP2015] 提高组 洛谷P2668 斗地主

题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响.每一局游戏中,一副手牌由n张牌组成.游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利. 现在,牛牛只想知道,对于自己的若干

洛谷 P2540 斗地主(NOIp2015提高组D1T3)

题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响.每一局游戏中,一副手牌由n张牌组成.游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利. 现在,牛牛只想知道,对于自己的若干

[NOIP2015] 提高组 洛谷P2680 运输计划

题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物 流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去.显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰. 为了鼓励科技创新,L 国国王同意小 P 的

[NOIp2015提高组]跳石头

OJ题号:洛谷2678 思路:贪心+二分. 从前往后扫,一旦这个石头到上一个选的石头的距离小于二分的值就把这块石头移走. 1 #include<cstdio> 2 #include<queue> 3 bool check(int mid,int m,int n,int *a) { 4 int p=0,w=0; 5 for(int i=1;i<=n;i++) { 6 if(a[i]-p<mid) { 7 w++; 8 } 9 else { 10 p=a[i]; 11 }