NWPU省赛选拔2017

热身赛:

A.题意:几个小孩围成一圈,从一个人手里传出这个球,可能向左,可能向右,问经过m轮传递传回这个人的方法数

题目类型:dp

解法:第i轮球在第j个人手里的方法数,即dp[i][j] = dp[i-1][j-1] + dp[i-1][j+1] 注意一下边界处理

Code:

#include <iostream>
#include <cstdio>
#include<cstring>
#define ll long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define MAX 100005

using namespace std;

int n,m,p,q,tree[4*100005];

int cnt=0,res,dp[50][50];
int main()
{
    cin>>n>>m;
    dp[0][1]=1;
    dp[1][1]=0;
    dp[1][2]=1;
    dp[1][n]=1;
    for(int i=2;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(j==1)
                dp[i][j]=dp[i-1][2]+dp[i-1][n];
            else if(j==n)
                dp[i][j]=dp[i-1][1]+dp[i-1][n-1];
            else
                dp[i][j]=dp[i-1][j-1]+dp[i-1][j+1];
        }
    }
    cout << dp[m][1] << endl;
    return 0;
}


B.疯狂涂色****

题目类型:枚举优化//。。。神奇

题意:有n个格子的纸条,有m条指令,第i条指令是将第(p*i+q)%n+1与(q*i+p)%n+1之间的格子图为颜色i,问执行完m条指令后最后的纸条的状态,无色为0;

解法:起初思路是线段树,然后lazy标记,更新段颜色,没写出来。。好像还会超时。正规思路很神奇 1.因为后涂的颜色会覆盖之前的颜色,因次我们可以倒着时间顺序,更新颜色,有颜色的格子就不再更新了,这里要写一个函数用来找某一个格子i的下一个没涂颜色的格子的位置的函数,不断更新 2.同时,再利用(p*i+q)%n+1是周期为n的函数,及在n次之内这个区间,一定会将n个格子覆盖完,因此最多执行n次操作;


C.题意:有3个人求到一点的最短距离和

解法:之前傻了,其实可以从终点跑一次最短路,加起来即可//三次最短路加一下


正式赛:

A. Height Oldering

题目链接

题意:先将队首的人放到那一排中,然后下一个人要找到比他高的第一个人,站到他前边,他后边的人就会退一步腾出空间(傻子一般的读题能力,这水题错的我一口老血);

解法:腾出空间的人,一定是比后来的那个人高的人,因此,我们只需要统计每一个数,前边比他高的人有几个,累加即可;

Code:

#include <iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<stdlib.h>
#include<algorithm>
#define ll long long
using namespace std;
int  n,a[25];
int T;

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        int cnt=0;
        for(int i=1;i<=20;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i=1;i<20;i++)
        {
            for(int j=i+1;j<=20;j++)
            {
                if(a[i]>a[j])cnt++;
            }
        }
         cout <<n<<' '<< cnt << endl;
    }

    return 0;
}

B.这题暴力很好写,不说了;

C.Happy Prime Prime

题目链接

题意:找出给定范围内符合条件数字的个数;

题意:初步思路:直接判断这个数是否符合条件,若是将这个数产生的数字全部标记为1,否标记为0,如果这个数字被使用过直接返回该值,否就重复上述步骤,避免了重复搜索,将该范围内符合条件的,数字打表;

好写(神)思路:数据范围是10000,猜下x,当一个数字循环某x次时,一定不符合条件,既然这样x就可以选择,刚好跑到时间上限就结束,好像x=50就够了(orz);

Code:

#include <iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int   n,m,a[25];
int T,jd[10005];
bool ispr[10005];
void Es()
{
    memset(ispr,true,sizeof(ispr));
    ispr[1]=false;
    for(int i=2; i<=10003/i; i++)
    {
        if(ispr[i])
        {
            for(int j=i*i; j<10003; j+=i)
            {
                ispr[j]=false;//printf("%d\n",i);
            }

        }
    }
}
/
int used[10005];

int judge(int m)
{
    int flag=0;
    if(!ispr[m])
        return 0;
    int tr=0,tm=m;
    for(int i=0;i<50; i++)
    {
        while(tm)
        {
            tr+=(tm%10)*(tm%10);
            tm/=10;
        }
        if(tr==1)
            return 1;
            tm=tr;
            tr=0;
    }
    return 0;
}

int main()
{
    Es();
    memset(jd,-1,sizeof(jd));
    memset(used,0,sizeof(used));
    for(int i=1; i<=10005; i++)
    {
        if(jd[i]==-1)
        {
            jd[i]=judge(i);//printf("---%d %d\n",i,jd[i]);
        }
    }
    //printf("%d %d %d %d\n",used[367],judge(367),jd[367],ispr[367]);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        if(jd[m]==1)printf("%d %d YES\n",n,m);
        else printf("%d %d NO\n",n,m);
    }
    return 0;
}

D.Mancala

题目链接

题意:每次输出第x种情况,的最后一个格子的数目,和从第一个到这一个的序列,向左扫遇到第i个数目为i时,将这个格子分给前  i  - 1个格子,和开头的箱子,如果最终全部可以在箱子里,则这个数列符合要求;

解法:倒着想,从左向右扫,碰到第i个格子为0则将其加i,前面的格子都取走一个,递推打表即可;

#include <iostream>
#include<cstdio>

using namespace std;

int a[2005][85];
int n,m;
int main()
{
    a[1][1]=1;
    a[2][1]=0,a[2][2]=2;
    a[3][1]=1,a[3][2]=2;
    a[4][1]=0,a[4][2]=1,a[4][3]=3;
    for(int i=2 ; i <= 2000 ; i++ )
    {
        int j;
        for(j =1 ; j <= 85 ; j++ )
        {
            if(a[i-1][j] == 0)
            {
                a[i][j] = j ;//printf("%d ",a[i][j]);
                break;
            }
            else
            {
                a[i][j] = a[i-1][j]-1;//printf("%d ",a[i][j]);
            }

        }
        j++;
        for( ; j <= 85 ; j++ )
        {
            a[i][j] = a[i-1][j] ;
            //printf("%d ",a[i-1][j]);
        }
       // printf("\n");
    }
    int x,T;
    scanf("%d",&T);
    for( int C = 1 ; C <= T ; C ++ )
    {
        scanf("%d%d",&n,&x);
        int sum = 0 ,k = 0 ,res1 ;
        for( ; sum < x ; )
        {
            sum+=a[x][k];
            res1=a[x][k];
            k++;
        }
        int y=0;
        printf("%d %d\n", C, res1);
        for(int i=1;i<k;)
        {
            int flag = 0;
            for( y = 0 ; y < 10 && i < k ; y ++ , i ++ )
            {
                if(flag)printf(" ");
                flag=1;
                printf("%d",a[x][i]);
            }
            printf("\n");
            if(i == k)break;
        }
    }
    return 0;
}


E.A Rational Sequence 

题目链接

题意:根据图示,找到这个数的下一个数;

解法:当p<q时,输出p1=q , q=p-q;当p==q时,输出1/2;当p>q,向上找x层到一个父节点是左儿子的,算出他的下一个节点,向下找x层左节点,输出这个数;(样例的10000000给的是1ooooooo。。。然后又没按这个判。。。无力)

Code;

#include <iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
#define ll long long
//样例错了error
using namespace std;
int T,n;

void solve(ll p1,ll q1)
{
    int cnt=0;
    if(p1==q1)
    {
        printf("1/2\n");return;
    }
    else if(p1>q1)
    {
        if(q1==1)
        {
            printf("1/%lld\n",p1+1);
            return ;
        }
        while(p1>q1)
        {
            p1=p1-q1;
            cnt++;
        }
        int a,b;
        a=p1,b=q1;
        p1=b;
        q1=b-a;
        while(cnt--)
        {
            q1=p1+q1;
        }
        printf("%lld/%lld\n",p1,q1);
        return ;
    }
    else if(p1<q1)
    {
        ll p=q1;
        ll q=q1-p1;
        printf("%lld/%lld\n",p,q);
        return ;
    }
}

ll p1,q1;
char s1[1000],s2[1000];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d/%d",&n,&p1,&q1);
        printf("%d ",n);

        solve(p1,q1);
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值