本次训练有关学习资料:
欧拉函数——小于n的数中与n互质数的数目
博弈论及算法实现(三种基础博弈)
快速幂(Java 实现代码)
A - A^B Mod C
Input
Output
Sample Input
Sample Output
题解:(快速幂)a的b次幂是成指数型增长的,很容易超出long型,所以我们需要每次乘后取模
import java.util.*;
public class Test01 {
public static void main(String [] args) {
Scanner cin=new Scanner(System.in);
long a=cin.nextLong();
long b=cin.nextLong();
long c=cin.nextLong();
System.out.println(mpow(a,b,c)%c);
}
/*
a的b次幂对c取模
因为a的b次幂是成指数型增长的,很容易超出long型,所以我们需要每次乘后取模
(a+b)%c--->((a%c) + (b%c)) %c (a*b)%c--->((a%c) * (b%c)) %c
*/
static long mpow(long a,long b,long c) {//快速幂求a^b%p
long s=(long)1;
while(b!=0) {
if((b&1)==1) s=s*a%c;
a=a*a%c;
b=b/2;//相当于b的二进制数向右移一位
}
return s;
}
}
B - 逆元
输入格式
输出格式
数据范围
Sample Input
Sample Output
题解: 据题意可知,可以判断P是否为质数,若为质数则可以直接通过等差数列求和求出结果即可,若不为质数则输出"AKCniubi".
import java.util.Scanner;
public class Test02 {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
/*
当 ax≡1(modb), x即为 a 在mod b 意义下的逆元。
简单来说逆元就是在mod某个数意义下的倒数例如5x≡1(mod3),x=2是满足10=1(mod3)所以称2是5在mod3意义下的逆元
*/
long p=cin.nextLong();
if (check(p)){//判断是否为质数,若为质数则直接调用等差数列求和公式求出结果即可
System.out.println(p*(p-1)/2);
}else {
System.out.println("AKCniubi");
}
}
static boolean check(long p) {//判断是否为质数
for (int i=2;i*i<=p;i++){
if (p%i==0){
return false;
}
}
return true;
}
}
C - 判决素数个数
Input
Output
Sample Input
Sample Output
题解:进行对X~Y之间的数枚举并构造函数判断每个数是否为素数即可
import java.util.Scanner;
public class Test03 {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int X=cin.nextInt();
int Y=cin.nextInt();
int count=0;
//进行对X~Y之间的数枚举即可
if (X<Y){
for (int i=X;i<=Y;i++){
if (check(i)){
count++;
}
}
}else {
for (int i=Y;i<=X;i++){
if (check(i)){
count++;
}
}
}
System.out.println(count);
}
static boolean check(int i) {//判断是否为素数
if (i==1){
return false;
}
for(int j=2;j*j<=i;j++) {
if(i%j==0)
return false;
}
return true;
}
}
D - 矩阵乘法
输入格式
输出格式
Sample Input
Sample Output
题解:根据矩阵乘法的定义求出C矩阵(A*B)并输出即可
import java.util.Scanner;
public class Test04 {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int n=cin.nextInt();
int m=cin.nextInt();
int k=cin.nextInt();
int A[][]=new int[n][m];
int B[][]=new int[m][k];
int C[][]=new int[n][k];
for (int i=0;i<n;i++){
for (int j=0;j<m;j++){
A[i][j]=cin.nextInt();
}
}
for (int j=0;j<m;j++){
for (int q=0;q<k;q++){
B[j][q]=cin.nextInt();
}
}
for (int i=0;i<n;i++){
for (int j=0;j<m;j++){
for (int q=0;q<k;q++){
C[i][q]+=(A[i][j]*B[j][q]);
}
}
}
for (int i=0;i<n;i++){
for (int j=0;j<k;j++){
System.out.print(C[i][j]+" ");
}
System.out.println();
}
}
}
E - Bash游戏
Input
Output
Sample Input
Sample Output
题解 :典型的巴什博弈(Bash Game)
import java.util.Scanner;
public class Test05 {
public static void main(String[] args) {//巴什博弈(Bash Game)
/*
巴什博弈(Bash Game)
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。
(1)最后取光者胜:
若n%(m+1)==0,后手必胜,否则先手必胜。
(2)最后取光者输:
若(n-1)%(m+1)==0,后手必胜,否则先手必胜。
*/
Scanner cin=new Scanner(System.in);
int T=cin.nextInt();
while (T-->0){
int N=cin.nextInt();
int K=cin.nextInt();
if (N%(K+1)==0){
System.out.println("B");
}else {
System.out.println("A");
}
}
}
}
F - 取石子游戏
Input
Output
Sample Input
Sample Output
题解:典型的威佐夫博弈(Wythoff's game)
import java.util.Scanner;
public class Test06 {
public static void main(String[] args) {//威佐夫博弈(Wythoff's game)
Scanner cin=new Scanner(System.in);
/*
威佐夫博弈(Wythoff's game):
有两堆各若干个物品,两个人轮流从任意一堆中取出至少一个或者同时从两堆中
取出同样多的物品,规定每次至少取一个,至多不限,最后取光者胜利。
做题思路:
设一堆为a,一堆为b,并且a为物品数量少的那一堆,而b为多的一堆。
如果(b-a)*1.618==a,则后手必胜;否则先手获胜。
由于某些题目精度要求较高,则1.618需换为((Math.sqrt(5.0)+1.0)/2.0).//记得用Math.floor()对其向上取整
(注:关于威佐夫博弈类型的题,不一定就是两堆,也可以是取到目标物品,并且目标物品是上下都有物品放置,即是一堆,但可以将其转化成上下堆为两堆,目标物品为最后取光的目标点.)
*/
while (cin.hasNext()){
int a=cin.nextInt();
int b=cin.nextInt();
double x=((Math.sqrt(5.0)+1.0)/2.0);
if (a>b){
if (Math.floor((a-b)*x)==b){
System.out.println("0");
}else {
System.out.println("1");
}
}else {
if (Math.floor((b-a)*x)==a){
System.out.println("0");
}else {
System.out.println("1");
}
}
}
}
}
G - Matches Game
Input
Output
Sample Input
Sample Output
题解:典型的尼姆博弈(Nimm Game)
import java.util.Scanner;
public class Test07 {
public static void main(String[] args) {
/*
尼姆博弈(Nimm Game):
有三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
尼姆博弈模型可以推广到:有n堆若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
这个游戏中的变量是堆数k和各堆的物品数N1,N2,……,Nk。对应的组合问题是,确定先手获胜还是后手获胜以及两个游戏人应该如何取物品才能保证自己获胜
解法:有n堆各若干个物品,两个人轮流从某一堆取任意多(或者最多m个,只需把每堆%m)的物品,规定每次至少取一个,多者不限,最后取光者得胜。
把每堆数量求异或a1^a2^…^ai’^…^an,结果为零,则先手必输,否则必赢
*/
Scanner cin=new Scanner(System.in);
while (cin.hasNext()){
int M=cin.nextInt();
int s=0;
for (int i=0;i<M;i++){
int a=cin.nextInt();
s^=a;
}
if (s==0){
System.out.println("No");
}else {
System.out.println("Yes");
}
}
}
}
H - 互质数的个数(一)
输入格式
输出格式
数据范围
Sample Input
Sample Output
题解:只需要删除掉能被n整除的数的个数即为互质数的个数
import java.util.Scanner;
public class Test08 {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int t= cin.nextInt();
while (t-->0){
long n=cin.nextLong();
long ans=n;
for (long i=2;i*i<=n;i++){
if (n%i==0){
ans=ans/i*(i-1);
while (n%i==0)
n/=i;
}
}
if (n>1){
ans=ans/n*(n-1);
}
System.out.println(ans);
}
}
}
I - Sumdiv
题目描述
输入格式
输出格式
样例输入
2 3
样例输出
15
样例解释
J - The Lottery
题目描述
输入格式
输出格式
样例输入
样例输出
题解: 找出所有被整除的个数,n-其个数即为答案
import java.util.Scanner;
public class Test11 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin=new Scanner(System.in);
while(cin.hasNext()) {
int n=cin.nextInt();
int m=cin.nextInt();
int p[]=new int[m];
for(int i=0;i<m;i++) {
p[i]=cin.nextInt();
}
int ans=0;
for(int i=1;i<(1<<m);i++) {
long t=1,cnt=0;
for(int j=0;j<m;j++) {
if((i>>j&1)!=0) {
t=lcm(t,p[j]);
if(t>n){
break;
}cnt++;
}
}
if(cnt%2!=0){
ans+=n/t;
}
else {
ans-=n/t;
}
}
System.out.println(n-ans);
}
}
private static long lcm(long t, long i) {
// TODO Auto-generated method stub
// System.out.println(gcd(t,i));
return (long) (t/gcd(t,i)*i);
}
private static long gcd(long t, long l) {
// TODO Auto-generated method stub
if(l==0)return t;
return gcd(l,t%l);
}
}
K - 组合数问题
输入格式
输出格式
数据范围
样例说明
样例1:
Sample Input
Sample Output
Sample Input 2
Sample Output 2
题解: 找出组合数中符合题意的个数并输出即可
import java.util.Scanner;
public class Test11 {
public static void main(String[] args) {
int a[][]=new int[2010][2010];
int b[][]=new int [2010][2010];
int n,m,ans,t,k;
Scanner scanner=new Scanner(System.in);
t=scanner.nextInt();
k=scanner.nextInt();
a[1][1]=1%k;
if (a[1][1]==0)
b[1][1]++;
for (int j=2;j<=2001;j++)
{
for (int q=1;q<=Math.min(j,2001);q++)
{
if (q==1)
a[j][q]=(a[j-1][q]+1)%k;
else
a[j][q]=(a[j-1][q]+a[j-1][q-1])%k;
if (a[j][q]==0)
b[j][q]=b[j][q-1]+1;
else
b[j][q]=b[j][q-1];
}
}
for (int i=1;i<=t;i++)
{
n=scanner.nextInt();
m=scanner.nextInt();
ans=0;
for (int j=1;j<=n;j++)
ans+=b[j][Math.min(m,j)];
System.out.println(ans);
}
}
}
L - 同余方程
输入格式
输出格式
数据范围
Sample Input
Sample Output
题意 :用扩展的欧几里得算法求对a在模b的意义下的逆元
import java.util.Scanner;
public class Test12 {
static long x=0;
static long y=0;
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
/*
当 ax≡1(modb), x即为 a 在mod b 意义下的逆元。
简单来说逆元就是在mod某个数意义下的倒数例如5x≡1(mod3),x=2是满足10=1(mod3)所以称2是5在mod3意义下的逆元
*/
long a=cin.nextLong();
long b=cin.nextLong();
if (1%(exgcd(a,b))==0){
while (x<=0){
x+=b;
y-=a;
}
System.out.println(x);
}
}
static long exgcd(long a, long b) {
if (b==0){
x=1;
y=0;
return a;
}
long result=exgcd(b,a%b);
long temp=x;
x=y;
y=temp-a/b*y;
return result;
}
}