noip2014 提高组

T1 生活大爆炸版 石头剪刀布 题目传送门

就是道模拟题咯

#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
int a,b,n;
int x[251],y[251],g[251],f[251];
int w[6][6]={{2,0,1,1,0},{1,2,0,1,0},{0,1,2,0,1},{0,0,1,2,1},{1,1,0,0,2}};
int main()
{
    n=read();
    int la=read(),lb=read();
    for(int i=0;i<la;i++) x[i]=read();
    for(int i=0;i<lb;i++) y[i]=read();
    for(int i=0;i<n;i++) g[i]=x[i%la],f[i]=y[i%lb];
    for(int i=0;i<n;i++){
        if(w[g[i]][f[i]]==0) b++;
        if(w[g[i]][f[i]]==1) a++;
    }
    printf("%d %d\n",a,b);
    return 0;
}

T2 联合权值 题目传送门

易证明和某一个点相连接的点 他们之间的距离就是2 所以我们可以枚举每一个点求值 当然一个一个点去求值太慢

这个时候我们发现了一个神奇的东西 他叫做——加法结合律! 问题就完美解决了.

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=450007,mod=10007;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
int n,first[M],cnt,ans,mx,w[M];
struct node{int to,next;}e[M];
void ins(int a,int b){cnt++; e[cnt].to=b; e[cnt].next=first[a]; first[a]=cnt;}
void insert(int a,int b){ins(a,b); ins(b,a);}
void dfs(int x){
    int mx1=0,mx2=0,sum=0;
    for(int i=first[x];i;i=e[i].next){
        int now=e[i].to;
        sum=(sum+w[now])%mod;
        if(w[now]>mx1) mx2=mx1,mx1=w[now];
        else if(w[now]>mx2) mx2=w[now];
    }
    mx=max(mx,mx1*mx2);
    for(int i=first[x];i;i=e[i].next){
        int now=e[i].to;
        ans=(ans+w[now]*((sum-w[now])%mod+mod)%mod)%mod;
    }
}
int main()
{
    int x,y;
    n=read();
    for(int i=1;i<n;i++) x=read(),y=read(),insert(x,y);
    for(int i=1;i<=n;i++) w[i]=read();
    for(int i=1;i<=n;i++) dfs(i);
    printf("%d %d\n",mx,ans);
    return 0;
}

T3 飞扬的小鸟 题目传送门

这就是道dp然而看了眼题解自己YY了半天才Ac......主要还是细节处理的问题吧?码力太差
首先很容易想到o(nm*m)的算法 直接推出答案 但是明显会超时 很容易得到f[i][j]=min{f[i-1][j-k*x]+k}
那较小的点会被计算很多次 我们可以由每个点的下面f【i】【j-x】的点推出答案 仍为最优解 这样就可以得出新的方程f[i][j]=min{f[i-1][j-x],f[i][j-x]}
复杂度降下来了就可以写了 当然还可以由上方下降得到 所以我们可以分两次递推得出答案 还有游戏到高度为M的时候不会结束 所以还得特殊考虑
最后 这个游戏不是codevs那里的东东嘛?

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxN=15007,maxM=1507,inf=1000000000;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
int f[maxN][maxM];
int n,m,k,x[maxN],y[maxN];
int down[maxN],up[maxN];
int main()
{
    n=read(); m=read(); k=read();
    for(int i=0;i<=n;i++) down[i]=0,up[i]=m+1;
    for(int i=0;i<n;i++) x[i]=read(),y[i]=read();
    for(int i=1;i<=k;i++){
        int p=read();
        down[p]=read(); up[p]=read();
    }
    for(int i=1;i<=n;i++)
     for(int j=0;j<=m;j++)
      f[i][j]=inf;
    f[0][0]=inf;//for(int i=1;i<=n;i++,printf("\n")) for(int j=1;j<=m;j++) printf("[%d] ",f[i][j]);
    //for(int i=1;i<=n;i++) printf("[%d %d]\n",down[i],up[i]);
    //for(int i=0;i<n;i++) printf("[%d %d]\n",x[i],y[i]);
    for(int i=1;i<=n;i++){
        for(int j=x[i-1];j<=m;j++) f[i][j]=min(f[i-1][j-x[i-1]]+1,f[i][j-x[i-1]]+1);
        for(int j=m-x[i-1];j<=m;j++) f[i][m]=min(f[i][m],f[i][j]+1),f[i][m]=min(f[i][m],f[i-1][j]+1);
        for(int j=down[i]+1;j<=up[i]-1;j++) if(j+y[i-1]<=m) f[i][j]=min(f[i][j],f[i-1][j+y[i-1]]);
        for(int j=1;j<=down[i];j++) f[i][j]=inf;;
        for(int j=up[i];j<=m;j++) f[i][j]=inf;
    }
    int ans=inf,cnt=k;
    for(int i=n;i;i--){
     for(int j=down[i]+1;j<=up[i]-1;j++) ans=min(ans,f[i][j]);
     if(ans<inf) break;
     if(up[i]!=m+1) cnt--;
    }
    if(cnt==k) printf("1\n%d",ans);
    else printf("0\n%d",cnt);
    return 0;
}

T4 无线网络发射器选址 题目传送门

枚举 计算 比较大小 没什么好说的吧

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
int d,n,ans,sum;
int map[155][155];
int main()
{
    int x,y,k;
    d=read(); n=read();
    for(int i=1;i<=n;i++) x=read(),y=read(),k=read(),map[x][y]=k;
    for(int i=0;i<=128;i++)
     for(int j=0;j<=128;j++){
         int now=0;
         for(int x=max(0,i-d);x<=min(i+d,128);x++)
          for(int y=max(0,j-d);y<=min(j+d,128);y++)
           now+=map[x][y];
         if(ans<now) ans=now,sum=0;
         if(ans==now) sum++;
     }
    printf("%d %d\n",sum,ans);
    return 0;
}

T5 寻找道路 题目传送门

首先可以顺着终点反向bfs一波 记录那些点是可以到达终点的

然后枚举每一个点看他的出边所指向的点是否能到达终点就好了

然后顺着可以走的点走一波spfa就解决问题了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=20007,maxN=400007,inf=0x3f3f3f3f;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
int first[M],book[M];
int d[M],h[M],cnt,S,T;
int n,m,q[M],use[M];
struct node{int to,next;}e[maxN];
void insert(int a,int b){cnt++; e[cnt].to=b; e[cnt].next=first[a]; first[a]=cnt;}
int sum,last[M];
struct note{int to,next;}e1[maxN];
void ins(int a,int b){sum++; e1[sum].to=b; e1[sum].next=last[a]; last[a]=sum;}
void bfs(){
    int head=0,tail=1;
    h[T]=1;
    while(head!=tail){
        int x=q[head++];
        for(int i=last[x];i;i=e1[i].next){
            int now=e1[i].to;
            if(!h[now]){h[now]=1; q[tail++]=now;}
        }
    }
    //for(int i=1;i<=n;i++) printf("[%d] ",h[i]); printf("\n");
    use[T]=use[S]=1;
//    for(int x=1;x<=n;x++,printf("\n"))
//     for(int i=first[x];i;i=e[i].next) printf("[%d] ",e[i].to);
    for(int x=1;x<=n;x++){
        int now=0;
        for(int i=first[x];i;i=e[i].next){
            now=e[i].to;
             if(!h[now]) break;
         }
         if(!h[now]) continue;
         use[x]=1;
    }
    //for(int i=1;i<=n;i++) printf("[%d] ",use[i]); printf("\n");
}
void spfa(){
    memset(d,0x3f,sizeof(d));
    int head=0,tail=1;
    d[S]=0; q[head]=S; book[S]=1;
    while(head!=tail){
        int x=q[head++]; book[x]=0; if(head>M) head=0;
        for(int i=first[x];i;i=e[i].next){
            int now=e[i].to; if(!use[now]) continue;
            //printf("[%d]\n",now);
            if(d[now]>d[x]+1){
                d[now]=d[x]+1;
                if(!book[now]){q[tail++]=now; book[now]=1; if(tail>M) tail=0;}
            }
        }
    }
}
int main()
{
    int x,y;
    n=read(); m=read();
    for(int i=1;i<=m;i++){
        x=read(); y=read();
        if(x!=y) insert(x,y),ins(y,x);
    }
    S=read(); T=read();
    q[0]=T; bfs();
    spfa();
    if(d[T]<inf) printf("%d\n",d[T]);
    else printf("-1\n");
    return 0;
}

T6 解方程题目传送门

这道题确实难 我是照着黄学长的思路来的 神犇传送门

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
int mod[5]={11261,19997,22877,21893,14843};
int n,m,len,sum;
int ans[1000005];
int a[5][105],pre[5][105],res[5][30005];
char s[10005];
int calc(int k){
    int sum=0;
    for(int i=0;i<=n;i++) sum=(sum+a[k][i]*pre[k][i])%mod[k];
    if(sum<0) sum+=mod[k];
    return sum;
}
int pd(int x){
    for(int k=0;k<5;k++)
     if(res[k][x%mod[k]]) return 0;
    return 1;
}
int main()
{
    n=read(); m=read();
    for(int i=0;i<=n;i++){
        scanf("%s",s+1); len=strlen(s+1);
        bool f=0;
        for(int k=0;k<5;k++){
            if(s[1]==‘-‘) f=1,a[k][i]=0;
            else a[k][i]=s[1]-‘0‘;
        }
        for(int k=0;k<5;k++){
            for(int j=2;j<=len;j++) a[k][i]=(a[k][i]*10+s[j]-‘0‘)%mod[k];
            if(f) a[k][i]=-a[k][i];
        }
    }
    for(int k=0;k<5;k++){
        for(int x=1;x<mod[k];x++){
            pre[k][0]=1;
            for(int i=1;i<=n;i++) pre[k][i]=(pre[k][i-1]*x)%mod[k];
            res[k][x]=calc(k);
        }
    }
    for(int i=1;i<=m;i++) if(pd(i)) ans[++sum]=i;
    printf("%d\n",sum);
    for(int i=1;i<=sum;i++) printf("%d\n",ans[i]);
    return 0;
}

时间: 2024-08-02 00:38:25

noip2014 提高组的相关文章

[NOIP2014] 提高组 洛谷P2038 无线网络发射器选址

题目描述 随着智能手机的日益普及,人们对无线网的需求日益增大.某城市决定对城市内的公共场所覆盖无线网. 假设该城市的布局为由严格平行的129 条东西向街道和129 条南北向街道所形成的网格状,并且相邻的平行街道之间的距离都是恒定值 1 .东西向街道从北到南依次编号为0,1,2…128 , 南北向街道从西到东依次编号为0,1,2…128 . 东西向街道和南北向街道相交形成路口,规定编号为x 的南北向街道和编号为y 的东西向街道形成的路口的坐标是(x , y ). 在 某 些 路口存在一定数量的公共

NOIP2014提高组总结

-by mps 尽管今年没参加NOIP2014提高组,但是做了一下,还是有感受的,在这里写出我500分的思路(满分以后会更改,毕竟能力有限......) Day 1 T1 生活大爆炸版石头剪子布 [题目大意] 石头剪子布大家都玩过,只不过这题加了“斯波克”和“蜥蜴人”,事实上还是蛮简单的,有基本逻辑推理常识和基本代码处理能力即可AC,放在PJ都是第一题的难度... 一般有三种做法: 文艺青年:写个矩阵来表示得失,注意要判断两次(甲对乙及乙对甲) 普通青年:16个if嵌套 二B青年:25个if无嵌

【学术篇】luogu1351 [NOIP2014提高组] 联合权值

一道提高组的题..... 传送门:题目在这里.... 现在都懒得更自己的blog了,怕是太颓废了_ (:з」∠) _ 好久没做题了,手都生了.(好吧其实是做题方面手太生了) 这题我都不想讲了,把代码一贴就算了呗.. 但还是要说说的.... 首先,题目里说:"无向连通图G 有n 个点,n - 1 条边." 我们可以知道这是一棵树(怕不是废话..),这样遍历的时候就能保证是O(n)级别了.. 找最大值 很简单,遍历树的时候找一下与每个点相连的点的最大值和次大值一乘就完了...显然这么贪心是

[NOIP2014] 提高组 洛谷P2296 寻找道路

题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条件1 的情况下使路径最短. 注意:图G 中可能存在重边和自环,题目保证终点没有出边. 请你输出符合条件的路径的长度. 输入输出格式 输入格式: 输入文件名为road .in. 第一行有两个用一个空格隔开的整数n 和m ,表示图有n 个点和m 条边. 接下来的m 行每行2 个整数x .y ,之间用一个

[NOIP2014] 提高组 洛谷P1941 飞扬的小鸟

题目描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败. 为了简化问题,我们对游戏规则进行了简化和改编: 游戏界面是一个长为n ,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度). 小鸟始终在游戏界面内移动.小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿横坐标方向右移的距离为1 ,竖直移动

[NOIP2014] 提高组 洛谷P1351 联合权值

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu ×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1 行,

NOIP2014提高组解方程

其实没有太难 但是不知道的话想不到 考场上大概有50分吧 1 #include <iostream> 2 #include <stdio.h> 3 #include <queue> 4 5 using namespace std; 6 7 int mod[7 + 2] = { 19 , 101 , 11261 , 19997 , 22877 , 21893 , 14843 }; 8 int n , m , ans[1000000 + 2]; 9 char a[100 +

[NOIP2014提高组]解方程

题目:BZOJ3751.洛谷P2312.UOJ#20.Vijos P1910.codevs3732. 题目大意:已知多项式方程: 求这个方程在[1, m]内的整数解(n 和 m 均为正整数). 解题思路:因为$0=0$(废话),能得出$0+x·p\equiv 0(mod\ p)$. 也就是当方程右边为0时,方程左边mod p为0. 但方程左边mod p等于0时,方程右边不一定等于0. 但是也不一定不等于0. 所以我们如果多引入几个p(最好是素数),对其进行测试,发现都为0的话,那我们就可以认为它

[NOIP2014] 提高组 洛谷P2312 解方程

题目描述 已知多项式方程: a0+a1x+a2x^2+..+anx^n=0 求这个方程在[1, m ] 内的整数解(n 和m 均为正整数) 输入输出格式 输入格式: 输入文件名为equation .in. 输入共n + 2 行. 第一行包含2 个整数n .m ,每两个整数之间用一个空格隔开. 接下来的n+1 行每行包含一个整数,依次为a0,a1,a2..an 输出格式: 输出文件名为equation .out . 第一行输出方程在[1, m ] 内的整数解的个数. 接下来每行一个整数,按照从小到

Noip2014 提高组 day1 T1&#183; 生活大爆炸版石头剪刀布

生活大爆炸版 石头剪刀布 描述 石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头.如果两个人出拳一 样,则不分胜负.在<生活大爆炸>第二季第 8 集中出现了一种石头剪刀布的升级版游戏. 升级版游戏在传统的石头剪刀布游戏的基础上,增加了两个新手势: 斯波克:<星际迷航>主角之一. 蜥蜴人:<星际迷航>中的反面角色. 这五种手势的胜负关系如表一所示,表中列出的是甲对乙的游戏结果. 现在,小 A 和小 B 尝试玩这种升级版的猜拳游戏.已知他们的出拳都是有周期性规律的