【胡策 9.16】Loi 队内胡策 Day1

emmmmm……..
发烧请假回家结果没有赶上qwq

这是第一场胡策题
由56级大佬们出题%%%

Problem 1 赛小城玩骰子

题目描述

众所周知,a和赛小城关系很好,赛小城经常与a交(gao)流(shi),今天一早,赛小城突发奇想,要和a玩骰子。
赛小城有一个骰子,如图1所示:
图1
数字1在上方,数字2在South(南)方位,数字3在East(东)方位,每一对相反方位的数字之和是7,按照上述.数字5在North(北)方位,数字4在west(西)方位,数字6在下方,如图l所示.数字4,5,6在图1中是看不到的。
骰子的初始位置如图1所示.按照下列 6条规则旋转骰子,规则如图2和图3所示:
图2
图2中所示的4条旋转规则是将骰子按照规则指定的方位旋转90度。图3中所示的2条旋转规则是将骰子沿水平方向分别向left(左)或Right(右)方位旋转90度

图3
图3.旋转规则Left(左)、Right(右)


a想知道,从图1所示的方位开始,根据给定的一系列规别连续的旋转骰子.在该过程中位于上方的数字之和(其中包括图1所示的初始方位上的数字1),赛小城被a的问题难住了,于是他向学习OI的你求助,你能帮帮他吗?

输入描述
第一行输入一个整数n,表示执行旋转的总步数。
第2~n-1行分别输入6条旋转规则中6个方位中的一个

输出描述
一行输出旋转过程中位于骰子上方的数字之和

样例输入

5
North
North
East
South
West

样例输出
21
数据范围及提示
对于100 %的数据 n≤1000


正解:

模拟。

#include<iostream>
#include<cstdio>
using namespace std;
int n,ans=1;
int fro=2,beh=5,lef=4,rig=3,upp=1,dow=6;
inline void move(char k)
{
    switch(k)
    {
        case('N'):
            upp=fro;fro=dow;
            beh=7-fro;dow=7-upp;
            break;
        case('E'):
            rig=upp;upp=lef;
            lef=7-rig;dow=7-upp;
            break;
        case('W'):
            upp=rig;rig=dow;
            dow=7-upp;lef=7-rig;
            break;
        case('S'):
            fro=upp;upp=beh;
            beh=7-fro;dow=7-upp;
            break;
        case('R'):
            fro=rig;rig=beh;
            lef=7-rig;beh=7-fro;
            break;
        case('L'):
            rig=fro;fro=lef;
            lef=7-rig;beh=7-fro;
            break;
    }
    ans+=upp;
}
int main()
{
    scanf("%d",&n);
    while(n--)
    {
        char oper[6];
        scanf("%s",&oper);
        move(oper[0]);
    }
    printf("%d\n",ans);
    return 0;
}

另一个版本emmm:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<cstdlib>
using namespace std;
const int max=0;
int m,n,k,tot,ans=1,UP=1,DOWN=6,FRONT=2,BACK=5,LEFT=4,RIGNT=3;

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

inline void out(int x)
{
    if(x>=10) out(x/10);
    putchar(x%10+'0');
    return;
}

int main()
{
    freopen("touzi.in","r",stdin);
    freopen("touzi.out","w",stdout);
    n=read();
    char c;
    while((c=getchar())!=EOF)
    {
        if(c=='N')
        {
            int T=UP;
            UP=FRONT,FRONT=DOWN,DOWN=BACK,BACK=T;
            ans+=UP;
        }
        else if(c=='S')
        {
            int T=UP;
            UP=BACK,BACK=DOWN,DOWN=FRONT,FRONT=T;
            ans+=UP; 
        }
        else if(c=='E')
        {
            int T=UP; 
            UP=LEFT,LEFT=DOWN,DOWN=RIGNT,RIGNT=T;
            ans+=UP;
        }
        else if(c=='W')
        {
            int T=UP;
            UP=RIGNT,RIGNT=DOWN,DOWN=LEFT,LEFT=T;
            ans+=UP;
        }
        else if(c=='R')
        {
            int T=FRONT;
            FRONT=RIGNT,RIGNT=BACK,BACK=LEFT,LEFT=T;
            ans+=UP;
        }
        else if(c=='L')
        {
            int T=FRONT;
            FRONT=LEFT,LEFT=BACK,BACK=RIGNT,RIGNT=T;
            ans+=UP;
        }
    }
    out(ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
 
 

    T2:

    Problem 2 赛小城玩游戏

    题目描述
    众所周知,赛小城是一个游戏发烧友。
    国庆节快到了,L国流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子没有雷,那么它里面的数字表示和它8连通的格子里面雷的数目。现在棋盘是n×2的,第一列里面某些格子是雷,而第二列没有雷。
    由于第一列的雷可能有多种方案满足第二列的数的限制,赛小城成功拿下所有记录之后,向你发下战书。你的任务即根据第二列的信息确定第一列雷有多少种摆放方案。

    输入描述
    第一行为N,第二行有N个数,依次为第二列的格子中的数。

    输出描述
    一个数,即第一列中雷的摆放方案数。

    样例输入
    2
    1 1

    样例输出
    2

    数据范围及提示
    对于40 %的数据 1<= N <= 20
    对于100 % 的数据 1<= N <= 10000


    正解:

    由某个点的前一点的数字和前两点的雷可以确定这个点是否防雷。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int sz = 23333;
    int b[sz],a[sz];
    int n,ans;
    inline void read(int &x)
    {
        x=0;
        int fl=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {if(ch=='-') fl=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')
        {x=x*10+ch-'0';ch=getchar();}
        x*=fl;
    }
    inline bool check()
    {
        for(int i=1;i<=n;++i)
        {
            b[i+1]=a[i]-b[i]-b[i-1];
            if(b[i+1]<0||b[i+1]>1) return 0;
        }
        if(b[n+1]!=0) return 0;
        return 1;
    }
    inline void write(int x)
    {
        if(x < 0)
            putchar('-'),x *= -1;
        if(x / 10)
            write(x / 10);
        putchar(x % 10 + '0');
    }
    int main()
    {
        read(n);
        for(int i=1;i<=n;++i)
            read(a[i]);
        if(a[1]==0)
            ans+=check();
        else if(a[1]==1)
        {
            b[1]=1;
            ans+=check();
            for(int j=1;j<=n;++j)
                b[j]=0;
            b[2]=1;
            ans+=check();
        }
        else
        {
            b[1]=1;
            b[2]=1;
            ans+=check();
        }
        write(ans);
        puts("");
        return 0;
    }
    /*
    只要第一个雷已经确定,那么后面所有的雷都是确定的,
    用 a 表示第二列的数字;
    用 b 表示第一列的雷,若为1则有雷,反之亦然
    所以枚举b[1]
    接下来  b[i] = a[i - 1] - b[i -1] - b[i - 2]
    判断中间的情况是否合法
    最后记得判断最后一个是否合法。
    如果最后b[n]+b[n-1]<>a[n],那么就能说明这种方案出错了,无需计入累加器
    */

    T3:

    Problem 3 赛小城学游泳

    题目描述
    众所周知,赛小城是一个胸怀大志,对游泳情有独钟的美男子。
    他第一次尝试游泳便是在广州的大海边。不知怎的,在沙滩上,由于古老东方的神秘力量,他被吸入了一个新的海底聚落。召唤他的是南海龙王,因为他想为自己选定一个继承人。但管理海底世界需要一定的组织能力。于是他为赛小城出了一个题:若有n个城市和m条单向道路,城市编号为1~n。每条道路连接两个不同的城市,n和m满足m <= n(n - 1)。给定两个城市a和b,可以给a到b的所有简单路(所有城市最多经过一次,包括起点和终点)排序:先按长度从小到大排序,长度相同时按照字典序从小到大排序。管理南海一直是赛小城儿时的梦,他的任务便是求出从a城市到b城市的第k短路。
    作为一名社会主义的好青年,助他一臂之力是你义不容辞的责任。

    输入描述
    输入的第一行为两个正整数 n 和 m,表示有 n 种化学物质和 m 条单向边。
    接下来 m 行,每行有 3 个正整数 x,y,z,表示从化学物质x和化学物质y之间的单向边长度为 z
    接下来一行,包括三个整数,a,b,k 表示赛小城所在的位置 a,终点所在的位置 b,和 k

    输出描述
    如果赛小城能通过第 k 短路从 S 到达 E,输出一个正整数,为第 k 短路的长度,如果不能通过第 k短路到达 E,输出“-1”(不包括引号)

    样例输入
    2 2
    1 2 5
    2 1 4
    1 2 2

    样例输出
    14

    数据范围及提示
    对于 30%的数据 k <= 2
    对于 70%的数据 1 <= N <= 100, 0 <= M <= 1000 1 <= a, b <= N, 1 <= c <= 100,k <= 100
    对于 100%的数据 1 <= N <= 1000, 0 <= M <= 100000 1 <= a, b <= N, 1 <= c <= 100,k<=1000


    k短路模板。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int sz = 233333;
    int h[sz],n,m,S,E,k;
    bool vis[sz],flag;
    
    int tot1,fir1[sz],nxt1[sz];
    int tot,fir[sz],nxt[sz];
    
    struct A
    {
        int pos;
        int g;
        bool operator < (const A &a) const
        {
            return g + h[pos] > a.g + h[a.pos];
        }
    };
    struct ed{
        int f,t,w;
    }l[sz],l1[sz];
    
    inline void build(int f,int t,int d)
    {
        l[++tot] = (ed){f,t,d};
        nxt[tot] = fir[f];
        fir[f] = tot; 
    } 
    inline void build1(int f,int t,int d)
    {
        l1[++tot1] = (ed){f,t,d};
        nxt1[tot1] = fir1[f];
        fir1[f] = tot1; 
    }
    queue<int>q1;
    void spfa()
    {
        memset(h,0x3f3f3f,sizeof(h));
        q1.push(E);
        h[E] = 0;
        while(!q1.empty())
        {
            int u = q1.front();
            vis[u] = 0;
            q1.pop();
            for(int i = fir1[u];i;i = nxt1[i])
            {
                int v = l1[i].t;
                if(h[v] > h[u] + l1[i].w)
                {
                    h[v] = h[u] + l1[i].w;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q1.push(v);
                    }
                }
            }
        }
    }
    priority_queue<A>q;
    void Astar()
    {
    /*  
        A t;t.pos=S,t.g=0;
        q.push(t);
        这里的写法和下面的那一行一样的
    */
        q.push((A){S,0});
        int cnt = 0;
        while(!q.empty())
        {
            A u = q.top();
            q.pop();
            if(u.pos==E)
            {
                cnt ++;
                if(cnt == k)
                {
                    flag = 1;
                    printf("%d",u.g);
                    return;
                }
            }
            for(int i = fir[u.pos];i;i = nxt[i])
            {
                int v = l[i].t;
                q.push((A){v,u.g + l[i].w});
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            build(a,b,c);
            build1(b,a,c);
        }
        scanf("%d%d%d",&S,&E,&k);
        if(S==E) k++;
        spfa();
        Astar();
        if(flag==0)
            puts("-1");
        return 0;
    }

    T4:

    Problem 4 赛小城学数学

    题目描述
    众所周知,赛小城是一个爱打瞌睡的好学生。
    这一天,他又在数学课上睡觉,这令数学老师忍无可忍。说是迟,那是快,数学老师一个箭步飞奔过去,敲醒了赛小城。并给出了一道极难的数学题,让他清醒一下。题意如下:从1 − N中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数最大可能是多少。赛小城退役已久,码力不够犯了难。于是赛小城找到了你,作为一名OIer,你能帮帮他么?

    输入描述
    一个数 N

    输出描述
    一行一个整数代表答案对100000007取模之后的答案。

    样例输入
    7

    样例输出
    144

    数据范围及提示
    对于30%的数据,1≤N≤100。
    对于50%的数据,1≤N≤5000。
    对于70%的数据,1≤N≤〖10〗^5。
    对于100%的数据,1≤N≤5×〖10〗^6。


    数论,嗯,没有然后了。
    分解质因数。

    正解:

    统计从1到N中每个质因数出现的次数,然后把每个质因数取它们的次数次幂(*还需要处理一下),然后相乘就是答案。

    如样例:
    1 2 3 4 5 6 7
    其中,4=2*2 ;6=2*3 ;
    质数有:2,3,5,7;

    对应出现的次数:

    2 -> 4(次)
    3 -> 2(次)
    5 -> 1(次)
    7 -> 1(次)

    *如果次数是奇数,则 次数– ,如果次数是偶数,则不变。

    处理后得:
    2 -> 4
    3 -> 2
    5 -> 0
    7 -> 0

    相乘得:(2^4)(3^2)(5^0)*(7^0)=144;

    首先筛一下素数,然后对于1~N的每个数x,出现的次数可记为:f(x)=(N/x)+(N/x^2)+(N/x^3)+…+(N/x^k);

    由此,可快速求得f(x);
    然后快速幂、相乘、%,即可。

    给出分解质因数的方法√【←好东西】
    void ask_jc(int n)
    {
        p = 0;
        int t = n;
        for(int i = 1;i <= tot && prime[i] <= n;i ++)
        {
            int c = prime[i];
            while(c <= n)
            {
                cnt[i] += t / c;
                c *= c;
                p = i;
            }
        }
    }
    

    标程:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    const int maxn=5000005;
    long long prime[maxn];
    bool not_prime[maxn];
    long long num[maxn];
    long long mod=100000007;
    long long ksm(long long a,long long b)
    {
        if(b==0) return 1ll;
        if(b==1) return a%mod;
        long long tmp=ksm(a,b/2)%mod;
        if(b%2==0)
            return ((tmp%mod)*(tmp%mod))%mod;
        else
            return ((((tmp%mod)*tmp)%mod)*(a%mod))%mod;
    }
    int main()
    {
        freopen("pow.in","r",stdin);
        freopen("pow.out","w",stdout);
        long long n;
        int cnt=0;
        long long ans=1;
        scanf("%I64d",&n);
        not_prime[1]=true;
        for(long long i=2;i<=n;i++)
        {
            if(!not_prime[i])
                prime[++cnt]=i;
            for(int j=1;j<=cnt;j++)
            {
                if(prime[j]*i>n) break;
                not_prime[prime[j]*i]=true;
                if(i%prime[j]==0) break;
            }
        }
        for(int i=1;i<=cnt;i++)
        {
            long long aa=n;
            while(aa!=0)
            {
                num[i]+=aa/prime[i];
                aa/=prime[i];
            }
        }
        for(int i=1;i<=cnt;i++)
        {
            if(num[i]%2==0)
            ans=(ans*ksm(prime[i],num[i]))%mod;
            else
            ans=(ans*ksm(prime[i],num[i]-1))%mod;       
        }
        printf("%I64d",ans);
        return 0;
    }
    • 1
      点赞
    • 1
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值