题目描述
石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头。如果两个人出拳一 样,则不分胜负。在《生活大爆炸》第二季第 8 集中出现了一种石头剪刀布的升级版游戏。 升级版游戏在传统的石头剪刀布游戏的基础上,增加了两个新手势: 斯波克:《星际迷航》主角之一。 蜥蜴人:《星际迷航》中的反面角色。 这五种手势的胜负关系如表一所示,表中列出的是甲对乙的游戏结果。
表一 石头剪刀布升级版胜负关系
现在,小 A 和小 B 尝试玩这种升级版的猜拳游戏。已知他们的出拳都是有周期性规律 的,但周期长度不一定相等。例如:如果小 A 以“石头-布-石头-剪刀-蜥蜴人-斯波克”长度 为 6 的周期出拳,那么他的出拳序列就是“石头-布-石头-剪刀-蜥蜴人-斯波克-石头-布-石头 -剪刀-蜥蜴人-斯波克-……”,而如果小 B 以“剪刀-石头-布-斯波克-蜥蜴人”长度为 5 的周 期出拳,那么他出拳的序列就是“剪刀-石头-布-斯波克-蜥蜴人-剪刀-石头-布-斯波克-蜥蜴人 -……” 已知小 A 和小 B 一共进行 N 次猜拳。每一次赢的人得 1 分,输的得 0 分;平局两人都 得 0 分。现请你统计 N 次猜拳结束之后两人的得分。
输入
第一行包含三个整数:N,NA,NB,分别表示共进行 N 次猜拳、小 A 出拳的周期长度, 小 B 出拳的周期长度。数与数之间以一个空格分隔。
第二行包含 NA 个整数,表示小 A 出拳的规律
第三行包含 NB 个整数,表示小 B 出拳 的规律。
其中,0 表示“剪刀”,1 表示“石头”,2 表示“布”,3 表示“蜥蜴人”, 4 表示 “斯波克”。数与数之间以一个空格分隔。
输出
输出一行, 包含两个整数,以一个空格分隔,分别表示小 A、小 B 的得分。
样例输入
10 5 6
0 1 2 3 4
0 3 4 2 1 0
样例输出
6 2
提示
【数据说明】
对于 100%的数据,0 < N ≤ 200,0 < NA ≤ 200, 0 < NB ≤ 200。
这个题模拟或者打表就好了,比赛时我是直接模拟做的,想到啥写啥,,,,打表的话把各种结果都实现存起来就行。
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
int n,x,y;
int a[210],b[210];
int main()
{
while(~scanf("%d%d%d",&n,&x,&y)){
met(a,0);
met(b,0);
int ans1=0;
int ans2=0;
for(int i=1;i<=x;i++)
sc(a[i]);
for(int i=1;i<=y;i++)
sc(b[i]);
for(int i=x+1;i<=n;i++)
a[i]=a[i-x];
for(int i=y+1;i<=n;i++)
b[i]=b[i-y];
for(int i=1;i<=n;i++){
if(a[i]==0){
if(b[i]==2||b[i]==3)
ans1++;
if(b[i]==1||b[i]==4)
ans2++;
}
else if(a[i]==1){
if(b[i]==0||b[i]==3)
ans1++;
if(b[i]==2||b[i]==4)
ans2++;
}
else if(a[i]==2){
if(b[i]==0||b[i]==3)
ans2++;
if(b[i]==1||b[i]==4)
ans1++;
}
else if(a[i]==3){
if(b[i]==2||b[i]==4)
ans1++;
if(b[i]==0||b[i]==1)
ans2++;
}
else if(a[i]==4){
if(b[i]==0||b[i]==1)
ans1++;
if(b[i]==2||b[i]==3)
ans2++;
}
}
printf("%d %d\n",ans1,ans2);
}
}
题目描述
无向连通图 G 有 n 个点,n-1 条边。点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi , 每条边的长度均为 1。图上两点(u, v)的距离定义为 u 点到 v 点的最短距离。对于图 G 上的点 对(u, v),若它们的距离为 2,则它们之间会产生Wu*Wv的联合权值。 请问图 G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权 值之和是多少?
输入
第一行包含 1 个整数 n。 接下来 n-1 行,每行包含 2 个用空格隔开的正整数 u、v,表示编号为 u 和编号为 v 的点 之间有边相连。 最后 1 行,包含 n 个正整数,每两个正整数之间用一个空格隔开,其中第 i 个整数表示 图 G 上编号为 i 的点的权值为 Wi。
输出
输出共 1 行,包含 2 个整数,之间用一个空格隔开,依次为图 G 上联合权值的最大值 和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对 10007 取余。
样例输入
5
1 2
2 3
3 4
4 5
1 5 2 3 10
样例输出
20 74
提示
【样例说明】
本例输入的图如上所示,距离为 2 的有序点对有(1,3)、(2,4)、(3,1)、(3,5)、(4,2)、(5,3)。
其联合权值分别为 2、15、2、20、15、20。其中最大的是 20,总和为 74。
【数据说明】
对于 30%的数据,1 <n ≤ 100;
对于 60%的数据,1 < n ≤ 2000;
对于 100%的数据,1 < n ≤ 200,000,0 < wi ≤ 10,000。
这个题个人感觉还是很难的,,比赛时看了一眼先跳过去了,结果就一直没做。刚刚又补了一下午才过的。。。
这个题我还是先天真的交了一发暴力N^2做的,,果然T了,,然后一直在优化。。
通过题目我们知道这个图是个树,既然是树,那么就不存在环,那么通过一个点连着的两个点的距离肯定就是2了,这两个点肯定不会相连,于是我们遍历这个图上的每个点,只要将这个点相连的点互相乘一下,再加起来就可以求出和来了, 而最大值可以在每次遍历的时候比较得出。。
而这个和具体的话要用到前缀和,乘法分配律的思想。
如果一个点E,有A,B,C,D四个点和它相连。那么这四个点互乘求和就是这个点E的答案,
这里就用A,B,C,D代表每个点的权值。
那么和ans=AB+AC+AD+BA+BC+BD+CA+CB+CD+DA+DB+DC
把重复的合并ans=2*(AB+AC+AD+BC+BD+CD)
=2*(A*(B+C+D)+B*(C+D)+C*D)
这样化简完是不是看出来了如何使用前缀和了,这里用一个变量ans1把每次遍历得到的值加起来即可。
具体看代码吧
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int mod=10007;
const int N = 2e5+10;
ll n,ans,maxn,a[N],head[N*2],tot;
struct edge
{
int v;
int next;
edge()
{
v=0;
next=0;
}
}e[N*4]; //链式前向星存图
void add(int x,int y)
{
e[++tot].next=head[x];
e[tot].v=y;
head[x]=tot;
}
void solve(int x)
{
ll ans1=0; //前缀和
ans1=a[e[head[x]].v]%mod; //先赋值给第一个点的权值
int s=e[head[x]].next; //第二条边
ll mm=a[e[head[x]].v]; //求最大值,题目没有说取模
for(int i=s;i;i=e[i].next){
ans=(ans+a[e[i].v]*ans1)%mod; //乘前缀和在累加
ans1=(ans1+a[e[i].v])%mod; //更新前缀和
maxn=max(maxn,a[e[i].v]*mm); //更新最大值
mm=max(mm,a[e[i].v]); //如果有比当前值大的就更新
}
}
void init()
{
tot=0;
ans=0;
maxn=0;
met(head,0);
met(a,0);
}
int main()
{
while(~scanf("%lld",&n)){
init();
int x,y;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
solve(i);
printf("%lld %lld\n",maxn,(ans*2)%mod);
}
}
题目描述
已知正整数 n 是两个不同的质数的乘积,试求出较大的那个质数。
输入
输入只有一行,包含一个正整数 n。
输出
输出只有一行,包含一个正整数 p,即较大的那个质数。
样例输入
21
样例输出
7
提示
【数据范围】
对于 60%的数据,6 ≤ n ≤ 1000。
对于 100%的数据,6 ≤ n ≤ 2*10e9。
这个用欧拉筛法应该可以做,注意一下开的数组的大小,筛出来的素数从小到大找,能被n整除,就n除以这个数得出答案。
但是还有另一种方法,根据质数的唯一分解定理,如果给出的n能被表示成两个质数的乘积,那么它就不能被合数整除,我们可以直接从2开始遍历到n,如果能被整除,同样除以这个数得出答案。
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
int n;
int main()
{
while(~scanf("%d",&n)){
for(int i=2;i<=n;i++){
if(n%i==0){
printf("%d\n",n/i);
break;
}
}
}
return 0;
}
题目描述
传说很遥远的藏宝楼顶层藏着诱人的宝藏。
小明历尽千辛万苦终于找到传说中的这个藏 宝楼,藏宝楼的门口竖着一个木板,上面写有几个大字:寻宝说明书。
说明书的内容如下: 藏宝楼共有 N+1 层,最上面一层是顶层,顶层有一个房间里面藏着宝藏。
除了顶层外, 藏宝楼另有 N 层,每层 M 个房间,这 M 个房间围成一圈并按逆时针方向依次编号为 0,…, M-1。
其中一些房间有通往上一层的楼梯,每层楼的楼梯设计可能不同。
每个房间里有一个 指示牌,指示牌上有一个数字 x,表示从这个房间开始按逆时针方向选择第 x 个有楼梯的房 间(假定该房间的编号为 k),从该房间上楼,上楼后到达上一层的 k 号房间。
比如当前房 间的指示牌上写着 2,则按逆时针方向开始尝试,找到第 2 个有楼梯的房间,从该房间上楼。
如果当前房间本身就有楼梯通向上层,该房间作为第一个有楼梯的房间。
寻宝说明书的最后用红色大号字体写着:“寻宝须知:帮助你找到每层上楼房间的指示 牌上的数字(即每层第一个进入的房间内指示牌上的数字)总和为打开宝箱的密钥”。 请帮助小明算出这个打开宝箱的密钥。
输入
第一行 2 个整数 N 和 M,之间用一个空格隔开。N 表示除了顶层外藏宝楼共 N 层楼, M 表示除顶层外每层楼有 M 个房间。
接下来 N*M 行,每行两个整数,之间用一个空格隔开,每行描述一个房间内的情况, 其中第(i-1)*M+j 行表示第 i 层 j-1 号房间的情况(i=1, 2, …, N;j=1, 2, … ,M)。第一个整数 表示该房间是否有楼梯通往上一层(0 表示没有,1 表示有),第二个整数表示指示牌上的数 字。注意,从 j 号房间的楼梯爬到上一层到达的房间一定也是 j 号房间。
最后一行,一个整数,表示小明从藏宝楼底层的几号房间进入开始寻宝(注:房间编号 从 0 开始)。
输出
输出只有一行,一个整数,表示打开宝箱的密钥,这个数可能会很大,请输出对 20123 取模的结果即可。
样例输入
2 3
1 2
0 3
1 4
0 1
1 5
1 2
1
样例输出
5
提示
【输入输出样例说明】
第一层: 0 号房间,有楼梯通往上层,指示牌上的数字是 2; 1 号房间,无楼梯通往上层,指示牌上的数字是 3; 2 号房间,有楼梯通往上层,指示牌上的数字是 4;
第二层: 0 号房间,无楼梯通往上层,指示牌上的数字是 1; 1 号房间,有楼梯通往上层,指示牌上的数字是 5; 2 号房间,有楼梯通往上层,指示牌上的数字是 2;
小明首先进入第一层(底层)的 1 号房间,记下指示牌上的数字为 3,然后从这个房间 开始,沿逆时针方向选择第3 个有楼梯的房间 2 号房间进入,上楼后到达第二层的2 号房间, 记下指示牌上的数字为 2,由于当前房间本身有楼梯通向上层,该房间作为第一个有楼梯的 房间。因此,此时沿逆时针方向选择第 2 个有楼梯的房间即为 1 号房间,进入后上楼梯到达 顶层。这时把上述记下的指示牌上的数字加起来,即 3+2=5,所以打开宝箱的密钥就是 5。
【数据范围】
N<=10000
M<=100
X<=1e6
这也是个模拟,不过这个模拟感觉有点恶心,比赛时就是因为这个题,,耽误了时间,这个也没过,,orz,就交晚了50多秒。。
模拟就好了,再输入的时候就把有楼梯的房间的个数记下来,然后每进入一层就先加上值,在绕就好了。。具体看代码吧,这个看一下应该就清楚了。
#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x) priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int mod=20123;
const int N=1e4+10;
int n,a[N][110],m,ans;
bool vis[N][110];
int main()
{
while(~scanf("%d%d",&n,&m)){
ans=0;
met(b,0);
met(vis,0);
met(a,0);
for(int i=1;i<=n;i++){
int t=0;
for(int j=0;j<m;j++){
sc(vis[i][j]);
sc(a[i][j]);
if(vis[i][j]) //有没有楼梯
a[i][m]++; //因为房间个数是从0~m-1,所以用第m个存这一层有楼梯的房间个数
}
}
int s;
sc(s);
for(int i=1;i<=n;i++){
ans=(ans+a[i][s]%mod)%mod;
int p=0;
for(int j=s;;j++){
if(j==m) //到头了,再转回去
j=0;
if(vis[i][j]==1)
p++;
int k=a[i][s]%a[i][m];
if(k==0) //如果取模为0,就代表要转的房间为这一层有楼梯的房间个数
k=a[i][m];
if(p==k){
s=j;
break;
}
}
}
printf("%d\n",ans);
}
}