2.18模拟赛总结

15 篇文章 0 订阅
7 篇文章 0 订阅

1:得分

题意:

【故事背景】
  众所周知,yk同学对数学非常痴迷。
  又是阳光明媚的一天,yk同学早早地起了床,又要开始刷数学题啦~
  现在yk面前摆着N道数学题,不同的题当然有不同的难度。为了挑战yk的极限,他希望越早地做出越难的题目。可是这个题目的完成情况既不能用完成的数目来衡量,也不能用完成的时间来衡量,所以yk自己定义了一个计算方法,来评价这次刷题的完成情况。
【题目描述】
  现在yk手上有N道题,他总共有T的时间来完成他们中的一些或全部。每道题有一个完成所需时间t[i]和一个难度系数c[i]。如果yk在剩余x个单位时间的时候开始做题i,并且能够完成,那么总分加上x*c[i]。现在yk要从这N道题中选出一些在T个单位时间内完成,并且按照某种顺序依次完成它们(yk每个单位时间只能做一道题,并且一旦他决定做某题就会一直做直到做完),那么他最多能够拿到多少分呢?

Solution:
 很明显的DP,不过打完01背包后发现有优先级,然后列式:如果先做i在做j,当前剩时间为x,那么就是x*c[i]+(x-t[i])*c[j]<x*c[j]+(x-t[j])*c[i]----c[i]*t[j]<c[j]*t[i]。那用这个排序,然后01背包。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
const int maxn=3005;
using namespace std;
int i,j,k,l,t,n,m,ans,nn,mm;
int f[10005],c[10005],d[maxn],e[maxn];
bool bz[10005][3005];
struct node{
    int a,b;
}a[maxn];
bool cmd(node a,node b){
    return a.a*b.b<a.b*b.a;
}
int main(){
    scanf("%d%d",&n,&m);
    fo(i,1,n){
        scanf("%d%d",&a[i].a,&a[i].b);
    }
    sort(a+1,a+1+n,cmd);
    fo(i,1,n){
        fod(j,m-a[i].a,0){
            f[a[i].a+j]=max(f[a[i].a+j],f[j]+(m-j)*a[i].b);
            ans=max(ans,f[a[i].a+j]);   
        }
    }
    printf("%d\n",ans);
}

2:荒岛野人

题意:

克里特岛以野人群居而著称。岛上有排列成环行的M个山洞。这些山洞顺时针编号为1,2,…,M。岛上住着N个野人,一开始依次住在山洞C1,C2,…,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来。每个野人i有一个寿命值Li,即生存的年数。下面四幅图描述了一个有6个山洞,住有三个野人的岛上前四年的情况。三个野人初始的洞穴编号依次为1,2,3;每年要走过的洞穴数依次为3,7,2;寿命值依次为4,3,1。
奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个山洞中,使得小岛一直保持和平与宁静,这让科学家们很是惊奇。他们想知道,至少有多少个山洞,才能维持岛上的和平呢?

Solution:
很明显的:要求(ax+b)mod p=(cx+d)mod p(x为年数,b,d为起始节点,a,c为每年走过的洞数,枚举洞的个数p(不小于所有的起始节点))。那么就是ax+b同余cx+d(mod p),(a-c)x同余d-b(mod p),设一个y满足(a-c)x+yp=d-b(y可能为负数)。因为可能还不是最简数,所以要除以他们(a-c,p)的最大公因数e,[(a-c)/e]x+[p/e]y=(d-b)/e,根据性质只有e整除(d-b)是才有解,然后扩展gcd,找出一个解,处理之后比如ax+by=c,那么还有解是a(x+b)+(y-1)b=c最后得解。
Code
#include<iostream>
#include<algorithm>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define fo(i,a,b) for(i=a;i<=b;i++)
const int maxn=200;
using namespace std;
int i,j,k,l,r,t,n,m,ans,mid,cc,d,w,e,lk;
int c[maxn],p[maxn],a[maxn];
int exgcd(int x,int y){
    int d,c;
    if(y==0){
        w=1;e=0;  
        return x;  
    }
    else{
        d=exgcd(y,x%y);
        c=w;
        w=e;
        e=c-x/y*e;
        return d;
    }
}
bool pan(int x){
    int i,j,k,l,yi,er;
    fo(i,1,n){
        fo(j,i+1,n){
            yi=p[i]-p[j];
            er=c[j]-c[i];
            d=exgcd(yi,x);
            if(er%d!=0)continue;
            w=w*er/d;e=x/d;k=0;
            k=w%e;
            if(k<0)k=k+abs(e);
            if(k<=a[i]&&k<=a[j])return 0;
        }
    }
    return 1;
}
int main(){
    scanf("%d",&n);
    fo(i,1,n){
        scanf("%d%d%d",&c[i],&p[i],&a[i]);
        lk=max(lk,c[i]);
    }
    fo(l,lk,1000000){
        if(pan(l)){
            printf("%d\n",l);
            return 0;
        }
    }
}

3:体育场

题意:

 观众席每一行构成一个圆形,每个圆形由300个座位组成,对300个座位按照顺时针编号1到300,且可以认为有无数多行。现在比赛的组织者希望观众进入场地的顺序可以更加的有趣,在门票上并没有规定每个人的座位,而是与这个圈中某个人的相对位置,可以坐在任意一行。
  门票上标示的形式如下:A B x 表示第B个人必须在A的顺时针方向x个位置(比如A坐在4号位子,x=2,则B必须坐在6号位子)。
  现在你就座位志愿者在入场口检票。如果拿到一张门票,与之前给定的矛盾,则被视为是假票,如果无矛盾,视为真票。现在给定该行入场观众的顺序,以及他们手中的门票,请问其中有多少假票?

Solution:
一看就是并查集,再加个权,注意连边就好了。
Code
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
const int maxn=50005;
int i,j,k,l,t,n,m,ans,y,s;
int f[maxn],g[maxn][303],p[maxn];
int gf(int x){
    if(f[x]==x)return x;
    else{
        int o=f[x];
        f[x]=gf(f[x]); 
        p[x]=(p[o]+p[x])%300; 
        return f[x];
    }
}
int main(){
    scanf("%d%d",&n,&m);
    fo(i,1,n)f[i]=i;
    fo(i,1,m){
        scanf("%d%d%d",&k,&l,&t);
        j=gf(k);s=gf(l);
        if(j!=s){
            f[s]=j;
            p[s]=(t+p[k]-p[l]+300)%300; 
        }
        else{
            if(((p[k]+t)%300)!=p[l])ans++;
        }
    }
    printf("%d\n",ans);
}

4:机器人M号

题意:

3030年,Macsy正在火星部署一批机器人。 第1秒,他把机器人1号运到了火星,机器人1号可以制造其他的机器人。 第2秒,机器人1号造出了第一个机器人——机器人2号。 第3秒,机器人1号造出了另一个机器人——机器人3号。 之后每一秒,机器人1号都可以造出一个新的机器人。第m秒造出的机器人编号为m。我们可以称它为机器人m号,或者m号机器人。 机器人造出来后,马上开始工作。m号机器人,每m秒会休息一次。比如3号机器人,会在第6,9,12,……秒休息,而其它时间都在工作。 机器人休息时,它的记忆将会被移植到当时出生的机器人的脑中。比如6号机器人出生时,2,3号机器人正在休息,因此,6号机器人会收到第2,3号机器人的记忆副本。我们称第2,3号机器人是6号机器人的老师。 如果两个机器人没有师徒关系,且没有共同的老师,则称这两个机器人的知识是互相独立的。注意:1号机器人与其他所有机器人的知识独立(因为只有1号才会造机器人),它也不是任何机器人的老师。 一个机器人的独立数,是指所有编号比它小且与它知识互相独立的机器人的个数。比如1号机器人的独立数为0,2号机器人的独立数为1(1号机器人与它知识互相独立),6号机器人的独立数为2(1,5号机器人与它知识互相独立,2,3号机器人都是它的老师,而4号机器人与它有共同的老师——2号机器人)。 新造出来的机器人有3种不同的职业。对于编号为m的机器人,如果能把m分解成偶数个不同奇素数的积,则它是政客,例如编号15;否则,如果m本身就是奇素数或者能把m分解成奇数个不同奇素数的积,则它是军人,例如编号 3, 编号165。其它编号的机器人都是学者,例如编号2, 编号6, 编号9。 第m秒诞生的机器人m号,想知道它和它的老师中,所有政客的独立数之和,所有军人的独立数之和,以及所有学者的独立数之和。可机器人m号忙于工作没时间计算,你能够帮助它吗? 为了方便你的计算,Macsy已经帮你做了m的素因子分解。为了输出方便,只要求输出总和除以10000的余数。

Solution
   答案的总和很显然是所有约数的phi和,求着个可以打个递推,也可以是用数学归纳法总结出是n-1。然后求前两个用f[i][j](前i个素数取j个素数的独立数个数)递推。
Code
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#define fo(i,a,b) for(i=a;i<=b;i++)
const int maxn=1005;
const int mo=10000;
using namespace std;
int i,j,k,l,t,n,m,ans;
int p[maxn],e[maxn],f[maxn][maxn],a[maxn],phi,yi,er;
bool bz;
int qsm(int x,int y){
    int o=1;
    while(y){
        if(y&1!=0) o=o*x%mo;
        x=x*x%mo;
        y=y/2;
    }
    return o;
}
int main(){
    scanf("%d",&k);ans=1;
    fo(i,1,k){
        scanf("%d%d",&p[i],&e[i]);
        ans=ans*qsm(p[i],e[i])%mo;
    }
    f[0][0]=1;
//  if(ans=1)ans=10000;
    fo(i,1,k){
        f[i][0]=1;
        fo(j,0,i){
            if(p[i]!=2)f[i][j]=(f[i-1][j-1]*(p[i]-1)%mo+f[i-1][j])%mo;
            else f[i][j]=f[i-1][j];
        }
    }
    fo(i,1,k){
        if(i%2)er=(er+f[k][i])%mo;
        else yi=(yi+f[k][i])%mo;
    }
    ans=(ans-yi-er+mo+mo-1)%mo;
    printf("%d\n",yi);
    printf("%d\n",er);
    printf("%d\n",ans%mo);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值