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);
}