NOIP2014提高组 自测

闲的慌也是手比较痒了,就打算找NOIP原题做一下,看看自己的水平,虽然大家都说2014年的题水

  日期: 2018.2.25
  时间: 7小时
  分数:450
  对于2014年提高组成绩,高出省一线10分,Rank约为60+

Day1


T1

生活大爆炸版石头剪刀布-链接

Solution

打表即可。

#include<cstdio>
using namespace std;
// win 1  dy 2 lose 3
int st[5][5]={{2,3,1,1,3},{1,2,3,1,3},{3,1,2,3,1},{3,3,1,2,1},{1,1,3,3,2}};
int ra[205];
int rb[205];

int main(){
    
    int N,A,B,ansa=0,ansb=0;
    scanf("%d%d%d",&N,&A,&B);
    for(register int i=0;i<A;++i){
        scanf("%d",&ra[i]);     
    }
    for(register int i=0;i<B;++i){
        scanf("%d",&rb[i]);
    }
    
    for(register int i=0;i<N;++i){
        int l = ra[i%A];int r = rb[i%B];
        if(st[l][r]==1)ansa++;
        if(st[r][l]==1)ansb++;
    }
    printf("%d %d",ansa,ansb);
    return 0;
}
socre:100

T2

联合权值-链接

emmmm这道题没想出正解,日后待更。

Solution(TLE)

邻接表建图,依次枚举所有点,然后遍历其子节点的子节点。

#include<cstdio>
#define MAXN 200005 
#define mod 10007
using namespace std;

inline int read(){
    int num=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    return num*f;
}

struct Node{
    int v,next;
}G[MAXN<<1];

int head[MAXN]={0};
int w[MAXN];
int N,tot=0;

long long max = -1;
long long sum = 0;

inline void add(int u,int v){G[++tot].v=v;G[tot].next=head[u];head[u]=tot;}

inline void dfs(int fa,int rt){
    for(register int i=head[rt];i;i=G[i].next){
        int v = G[i].v;if(v==fa)continue;
        long long W = (long long)w[fa]*w[v];
        if(W>max)max=W;
        sum = (sum+W)%mod;
    }
}

int main(){
    
    N=read();
    
    for(register int i=1;i<=N<<1;++i)G[i].next=0;
    for(register int i=1;i<=N;++i)head[i]=0;
    
    int u,v;
    for(register int i=1;i<N;++i){
        u=read();v=read();add(u,v);add(v,u);    
    }
    
    for(register int i=1;i<=N;++i){
        w[i]=read();
    }
    
    for(register int i=1;i<=N;++i){
        for(register int j=head[i];j;j=G[j].next)dfs(i,G[j].v);
    }
    
    printf("%lld %lld",max,sum);
    return 0;
}
score:70
补充

N个节点N-1条边的无向连通图——树,则可以往此方面去想正解,但是自测时没有想出。


T3

飞扬的小鸟-链接

看上去这道题就是个dp,但是技艺不精不会写,所以只能试着去交一个暴力。

Solution (TLE)

对于每一个时刻,都有不点和点i下的操作,则根据此进行爆搜。

#include<cstdio>
#define MAXN 100005
using namespace std;

inline int read(){
    int num=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    return num*f;
}

int N,M,K;
int l[MAXN],r[MAXN];
int x[MAXN],y[MAXN];
int map[MAXN];

int maxcnt = 0;
int min = 2147483647;

inline bool dfs(int p,int h,int count,int num){
    
    if(h>M)h=M;
    if(h<=0)return false;
    if(map[p]!=0){
        if(h>l[map[p]]&&h<r[map[p]])count++;
        else return false;
    }
    if(count>maxcnt)maxcnt=count;
    if(num>=min)return false;
    if(p==N){
        min = num;
        return true;
    }
    
    bool f = false;
    if(dfs(p+1,h-y[p],count,num))f = true;
    int last = 0;
    for(register int i=1;h+i*x[p]<=M;++i){
        if(dfs(p+1,h+i*x[p],count,num+i))f = true;
        last = i;
    }
    if(last*x[p]<M)
        if(dfs(p+1,h+(last+1)*x[p],count,num+last+1))f = true;
    return f;
}
int main(){
      
    int p;
    N=read();M=read();K=read();
    for(register int i=0;i<N;++i)x[i]=read(),y[i]=read();
    for(register int i=1;i<=K;++i){
        p=read();map[p]=i;l[i]=read();r[i]=read();
    }
   
    bool f = false;
    for(register int high = 1;high<=M;++high){
        if(dfs(0,high,0,0))f = true;
    }
    
    if(f)printf("1\n%d",min);
    else printf("0\n%d",maxcnt);
    return 0;
}
score:50

DAY1总分:220


DAY 2


T1

无线网络发射器选址-链接

Solution

由于数据范围比较小,所以直接选用暴力枚举所有点,然后以此为中心枚举周边即可。

#include<cstdio>
using namespace std;
int map[130][130];
int d,n;

int main(){
    
    for(register int i=0;i<129;++i)
    for(register int j=0;j<129;++j)
        map[i][j] = 0;
    
    scanf("%d%d",&d,&n);
    for(register int i=0;i<n;++i){
        int x,y,k;
        scanf("%d%d%d",&x,&y,&k);
        map[x][y] = k;
    }
    
    int ans = 0;
    int max = -1;
    
    for(register int i=0;i<129;++i)
        for(register int j=0;j<129;++j){
            
            int count = 0;
            
            for(register int x=i-d;x<=i+d;++x)
                for(register int y=j-d;y<=j+d;++y){
                    if(x>128||y>128||x<0||y<0)continue;
                    count+=map[x][y];
                }
            if(count==0)continue;
            if(count>max){
                max = count;
                ans = 1;
            }
            else if(count==max)ans++;
        }
    
    printf("%d %d",ans,max);
    return 0;
        
}
score:100
补充:

此题也可以使用前缀和或差分。


T2

寻找道路-链接

Solution

可考虑使用BFS进行找最短路,但是对于节点的排除,可以建反图然后从终点开始BFS,遍历到的节点即为可以直接或间接达到终点的节点。

对于自己出边上的节点判断,可以在反BFS时给访问到的节点的入边节点+1,则代表它多了一个能到达终点的出边节点,最后遍历一下,哪些数目不对,则代表自己存在不能到达终点的出边节点。

#include<cstdio>
#define MAXN 10005
#define MAXM 200005
using namespace std;

inline int read(){
    int num=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    return num*f;
}

struct SIZE{
    int v,next;
}G[MAXM],g[MAXM];

int head1[MAXN];
int head2[MAXN];
struct NODE{
    int count,size,vis;
}Node[MAXN];

int queue[MAXN];

int N,M;
int tot=0;
int s,t;

inline void add(int u,int v){
    G[++tot].v=v;G[tot].next=head1[u];head1[u]=tot;
    g[tot].v=u;g[tot].next=head2[v];head2[v]=tot;
}

inline void BFS1(){
    Node[t].vis=1;
    queue[1]=t;
    int l = 1,r = 1;
    while(l<=r){
        int cnt = 0;
        for(register int i=l;i<=r;++i){
            int u = queue[i];
            for(register int j=head2[u];j;j=g[j].next){
                int v = g[j].v;
                Node[v].count++;
                if(Node[v].vis==1)continue;
                cnt++;
                Node[v].vis=1;
                queue[r+cnt]=v;
            }
        }
        l=r+1;r+=cnt;
    }
}
inline void check(){
    for(register int i=1;i<=N;++i){
        if(Node[i].count!=Node[i].size)Node[i].vis=0;
    }
}
int main(){
    
    
    N=read();M=read();
    
    for(register int i=1;i<=N;++i){
        head1[i]=0;head2[i]=0;Node[i].count=0;
        Node[i].size=0;Node[i].vis=0;
    }
    for(register int i=1;i<=M;++i){
        G[i].next=0;g[i].next=0;
    }
    
    int u,v;
    for(register int i=1;i<=M;++i){
        u=read();v=read();add(u,v);
        Node[u].size++;
    }
    s = read();t = read();
    
    BFS1();
    
    if(Node[s].vis==0){
        puts("-1");
        return 0; 
    }
    check();
    if(Node[s].vis==0){
        puts("-1");
        return 0; 
    }
    
    int l=1,r=1;
    queue[1]=s;
    Node[s].vis=2;
    int ans = 0;
    while(l<=r){
        ans++;
        int cnt = 0;
        for(register int i=l;i<=r;++i){
            int u = queue[i];
            for(register int j=head1[u];j;j=G[j].next){
                int v = G[j].v;
                if(Node[v].vis==0||Node[v].vis==2)continue;
                if(v==t){
                    printf("%d",ans);
                    return 0;
                }
                cnt++;
                queue[cnt+r]=v;
                Node[v].vis=2;
            }
        }
        l=r+1;r+=cnt;
    }
    puts("-1");
    return 0;
}
score:100

T3

解方程-链接

Solution

高精度,具体做法想不出来,写了个30分的暴力交上去。

#include<cstdio>
using namespace std;
long long a[105];
int answer[1000005];

int N,M;
    
inline bool C(int x){
    long long sum = 0;
    long long mul = 1;
    for(register int i=0;i<=N;++i){
        sum += mul*a[i];
        mul*=x; 
    }
    if(sum==0)return true;
    else return false;
}
int main(){

    scanf("%d%d",&N,&M);
    for(register int i=0;i<=N;++i)scanf("%lld",&a[i]);
    int ans = 0;
    
    for(register int i=1;i<=M;++i){
        if(C(i)){
            ans+=1;
            answer[ans]=i; 
        }
    }
    printf("%d\n",ans);
    for(register int i=1;i<=ans;++i)printf("%d\n",answer[i]);
    return 0;
}

#### score:30

### DAY2总分:230

总分:450


总结

肯定

自己写暴力越来越熟练了!!~

否定

对于难题没有更好的办法,仍需努力!

2018.2.25(开学)

转载于:https://www.cnblogs.com/Neworld2002/p/8470795.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值