import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO 自動生成的方法存根
Scanner sc=new Scanner(System.in);
int t=sc.nextInt();
for(int i=0;i<t;i++)
{
long b=sc.nextLong();
long c=1000000007;long a=2;
long res = 1;
a %= c;
for (; b != 0; b /= 2) {
if (b % 2 == 1)
res = (res * a) % c;
a = (a * a) % c;
}
System.out.println(res);
}
}
}
複製代碼
遞歸版(用的比較多)php
import java.util.Scanner;
public class Main {
static long c=1000000007;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t=sc.nextInt();
for(int i=0;i<t;i++)
{
long a=2;
long b=sc.nextLong();
long value=divide((long)2,b);
System.out.println(value%c);
}
}
private static long divide(long a,long b) {
if(b==0)return 1;
else if(b%2==0) {return divide((a%c)*(a%c),b/2)%c;}
else return a%c*divide((a%c)*(a%c),(b-1)/2)%c;
}
}
複製代碼
題目連接 核心思想爲: java
static int [][] multiplication(int a[][],int b[][]){//
int x=a.length;//a[0].length=b.length 爲知足條件
int y=b[0].length;//肯定每一排有幾個
int c[][]=new int [2][2];
for(int i=0;i<x;i++)
for(int j=0;j<y;j++)
{
//須要肯定每個元素
//c[i][j];
for(int t=0;t<b.length;t++)
{
c[i][j]+=(a[i][t]%10000)*(b[t][j]%10000);
c[i][j]%=10000;
}
}
return c;
}
複製代碼
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO 自動生成的方法存根
Scanner sc=new Scanner(System.in);
while(sc.hasNext())
{
int n=sc.nextInt();
if(n==-1)break;
if(n==0) {System.out.println(0);}
else {
n-=1;//
int a[][]= {{1,1},{1,0}};
int b[][]={{1,0},{0,1}};//單位矩陣
int time=0;
while(n>0)
{
if(n%2==1)
{
b=q(a, b);
}
a=q(a, a);n/=2;
}
System.out.println((b[0][0]));
}
}
}
static int [][] q(int a[][],int b[][]){//
int value1=a[0][0]*b[0][0]%10000+a[0][1]*b[1][0]%10000;//左上
int value2=a[0][0]*b[0][1]%10000+a[0][1]*b[1][1]%10000;//左上
int value3=a[1][0]*b[0][0]%10000+a[1][1]*b[1][0]%10000;//左上
int value4=a[1][0]*b[0][1]%10000+a[1][1]*b[1][1]%10000;//左上
int c[][]=new int [2][2];
c[0][0]=value1%10000;
c[0][1]=value2%10000;
c[1][0]=value3%10000;
c[1][1]=value4%10000;
return c;
}
}
複製代碼
拓展歐幾里得模板 參考:哈爾濱理工大學ACM培訓資料彙編/ACM-ICPC培訓資料彙編* 基本原理 :設 a 和 b 不全爲 0,==則存在整數 x,y 使得 xa+yb=gcd(a,b)=c== 對於展轉相除法的最後一項 此時 b=0,則 gcd(a,b)=1a+0b,(這個a,b是通過gcd的最後一項a,b)ios
由於gcd(a,b)=gcd(b,a%b)
c++
則有x *a+y *b=x1 *b+y1 * (a%b)
將等式右邊變形,git
b *x1+(a%b) *y1=b *x1+(a-(a/b) *b) *y1=a *y1+b *(x1-(a/b) *y1)
github
則,x=y1,y=x1-(a/b) *y1
則可由後向前迭代獲得 x,y算法
解題思路 :數組
對於擴展歐幾里德定理的題,通常都須要進行必定的推導以後獲得一個形式爲 xa+yb=c 的方程,而後根據 c 肯定解是否存在, 若是 c 能夠被 gcd(a,b)整除,那麼方程有 解,不然方程無解。 並且所得的解是不惟一的,對於一組解 x0,y0 則其全部解能夠表示爲 x=x0+b/gcd(a,b)*t,y=y0-a/gcd(a,b)*t,t=0,+1,+2……
通常會要求找出 x 或者 y 的最小正整數 解,這個時候須要作一些調整。bash
總的來講。遞歸是一來一回的過程,在gcd中,咱們只用到了去的過程,求的最大公約數,而在exgcd中,咱們發現了在來的過程當中,某些數按照必定的規則變化,能夠獲得咱們想要的結果而已。markdown
static long x=0,y=0;
...
static long extgcd(long a,long b) {
if(b==0) {x=1;y=0;return a;}
long ans=extgcd(b, a%b);
long team=x;
x=y;
y=team-a/b*y;
return ans;
}
複製代碼
求逆元: 從拓展歐幾里得中知道能夠求ax+by=c,通常是解決這類問題
當a,b互質時候。c必定等於1.由於gcd(a,b)=1,c必須被gcd整除,那麼若是有解必定是1.
那麼ax+by=1.
求逆元通常形式(求a關於1mod m的逆元)
ax≡1 (mod m). x就是所求的逆元
變形爲 ax+bm=1
這樣就能夠運用拓展歐幾里得(可是x要大於0處理)
static long x=0;static long y=0;//全局變量
......
long q=tgcd(a,b);
// long x1=x;
if(1%q!=0) {out.println("Not Exist");}
else {
while(x<=0){//x*a+y*b=1 要求x>0這樣而且要求x最小,那麼這樣操做就至關於+ab-ab操做。剛開始還沒明白
x+=b;
y-=a;
}
system.out.println(x);}//
static long tgcd(long a,long b) {
if(b==0) {x=1;y=0;return a;}
long ans=tgcd(b,a%b);
long team=x;
x=y;
y=team-a/b*y;
// System.out.println(x);
return ans;
}
複製代碼
還有用小費馬能夠求逆元,就不介紹了。
杭電2669 給a,b求Xa + Yb = 1.若是沒有則輸出sorry。 能夠經過拓展歐幾里得指導Xa + Yb = gcd(a,b). 不言而喻要判斷gcd(a,b)是否等於1.若是不等於1,那麼就是sorry。若是等於一,那麼還不能讓x小於0,要對x,y進行加減操做知足x>0;拓展歐幾里得是經過遞歸從下往上進行運算。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
/*
* 拓展歐幾里得
*/
public class hdu2669 {
static long x=0;static long y=0;
public static void main(String[] args) throws IOException {
// TODO 自動生成的方法存根
StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while(in.nextToken()!=StreamTokenizer.TT_EOF)
{
long a=(long)in.nval;
in.nextToken();
long b=(long)in.nval;
long q=tgcd(a,b);
if(1%q!=0) {out.println("sorry");}//gcd要和要求相等(這裏等於1)
else {
while(x<=0){//x*a+y*b=1 要求x>0這樣而且要求x最小,那麼這樣操做就至關於+ab-ab操做。剛開始還沒明白
x+=b;
y-=a;
}
out.println(x+" "+y);}//
out.flush();
}
}
static long tgcd(long a,long b)
{
if(b==0) {x=1;y=0;return a;}
long ans=tgcd(b,a%b);
long team=x;
x=y;
y=team-a/b*y;
return ans;
}
}
複製代碼
兩隻青蛙在網上相識了,它們聊得很開心,因而以爲頗有必要見一面。它們很高興地發現它們住在同一條緯度線上,因而它們約定各自朝西跳,直到碰面爲止。但是它們出發以前忘記了一件很重要的事情,既沒有問清楚對方的特徵,也沒有約定見面的具體位置。不過青蛙們都是很樂觀的,它們以爲只要一直朝着某個方向跳下去,總能碰到對方的。可是除非這兩隻青蛙在同一時間跳到同一點上,否則是永遠都不可能碰面的。爲了幫助這兩隻樂觀的青蛙,你被要求寫一個程序來判斷這兩隻青蛙是否可以碰面,會在何時碰面。
咱們把這兩隻青蛙分別叫作==青蛙A和青蛙B==,而且規定緯度線上東經0度處爲原點,由東往西爲正方向,單位長度1米,這樣咱們就獲得了一條首尾相接的數軸。設青蛙A的出發點座標是x,青蛙B的出發點座標是y。青蛙A一次能跳m米,青蛙B一次能跳n米,兩隻青蛙跳一次所花費的時間相同。緯度線總長L米。如今要你求出它們跳了幾回之後纔會碰面。 Input
輸入只包括一行5個整數x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。 Output 輸出碰面所須要的跳躍次數,若是永遠不可能碰面則輸出一行"Impossible" Sample Input 1 2 3 4 5 Sample Output 4
分析一下設見面時間爲t。青蛙A的位置是x+mt;青蛙B的位置是y+nt;兩隻青蛙項目,那麼說明兩隻青蛙之間要麼誰比誰多整數圈數。那麼就獲得x+mt-(y+nt)=k*L.變形一下(m-n)t-kL=(y-x).這就是m-n,L,y-x分別已知,而t和k未知,求最少的t.(t越少跳的越少。)
那麼設m-n=a,L=b,t=X,-k=Y,y-x=c.原始就是aX+bY=c,其中a,b,c已知,求X最小正整數。你要判斷c是否與gcd(a,b)互質,若是不互質則沒有結果。
接着你求出的初始X是gcd(a,b)的狀況,你要判斷c是不是gcd的倍數,若是跟他互質,那麼涼涼,不可能遇到,不知足extgcd的條件,若是是倍數。假設n倍,你能夠你能夠nXa,nYa,c至關於同時擴大倍的一種解,可是這不必定是最優解,你須要根據實際加減操做找到最小正解!
ac代碼
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class poj1061 {
static long X=0; static long Y=0;
public static void main(String[] args) throws IOException {
// TODO 自動生成的方法存根
StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
in.nextToken();long x=(long)in.nval;//A起始位置
in.nextToken();long y=(long)in.nval;//B起始位置
in.nextToken();long m=(long)in.nval;//A的速率
in.nextToken();long n=(long)in.nval;//B的速率
in.nextToken();long L=(long)in.nval;//長度
long a=m-n;
long c=y-x;
long b=L;
if(a<0) {a=-a;c=-c;}
long res=extgcd(a,b);// res=gcd(a,b)
//c必須是res的倍數,若是互質的話就不知足拓展歐幾里得的方程式,而對應的結果首先要跟着倍數擴大
if(c%res!=0) {out.println("Impossible");}
else {
/* * 可能難理解一點 * x=x0+(b/gcd(a,b))*t * x=x0+(b/res)*t找到最小的正整數x,那麼就是x%(b/res)了,若是小於0就是(x%b/res)+b/res了 */
X=X*(c/res);
long t=b/res;
if(X>=0)
X=X%t;
else
X=X%t+t;
out.println(X);
}
out.flush();
}
private static long extgcd(long a, long b) {
if(b==0)
{
X=1;Y=0;
return a;
}
long res=extgcd(b, a%b);
long team=X;
X=Y;
Y=team-(a/b)*Y;
return res;
}
}
複製代碼
問題:斷定一個數是否爲素數:
static boolean isprime(int value){
for(int i=2;i<value;i++)
{
if(value%i==0)
{return false;}
}
return true;
}
複製代碼
暴力從開始判斷的方法。複雜度O(n)。當數據大於1e7左右基本就爆了。更別說多組輸入了
對於一個數n若是==不是素數==,必定有a*b=n(a<b);a<根號n,b>根號n,因此只要出現必定是成雙成對。因此你只要==找到1個==就能說明這個數不是素數。因此從開始遍歷到a是最省時的方法。由於a是log級。算法複雜度爲O(logn)因此代碼爲:
static boolean isprime(int value) {
for(int i=2;i*i<value+1;i++)
{
if(value%i==0)
{return false;}
}
return true;
}
複製代碼
這種狀況可以基本單輸入的素數問題。可是遇到多個輸入確定也會GG的。
問題:多個輸入,問關於素數相關的問題。 若是用上述方法確定爆。多組輸入的最好解決辦法是打表。至於打表,若是上述的打表nlogn打表的話會TLE,因此就要換一種思考方式。
埃氏篩的核心思想就是==將素數的倍數肯定爲合數==。對於一個從2開始連續數據,咱們假設其中每個都是素數。若是一個數爲素數,那麼這個數的倍數必定也是素數。因此算法大體流程: 2: [i=(2+2)—>(+2)數組尾],4,6,8,10 * * 不是素數 3: [i=(3+3)—>(+3)數組尾],6,9,12 * * 不是素數 4: [i=4]不是素數,跳過 5: . . . . . . . . . . . . 這個到除了前面幾回的計算量多一點,到後面隨着數據增大對整個複雜度相加是比較小的,算法複雜度爲O(nloglogn);別小瞧多的這個logn,數據量大一個log可能少很多個0,那時間也是十倍百倍甚至更多的差距。 具體代碼爲
static boolean isprime[];
static long prime[];
static void getprime() {
prime=new long[100001];//記錄第幾個prime
int index=0;
isprime=new boolean [1000001];
for(int i=2;i<1000001;i++)
{
if(!isprime[i])
{
prime[index++]=i;
}
for(int j=i+i;j<1000000;j=j+i)//他的全部倍數都over
{
isprime[j]=true;
}
}
}
複製代碼
對於上述的埃氏篩,雖然能解決大部分的問題。可是不難發現裏面仍是有挺多不夠精簡的地方,好比有的地方會重複訪問。而歐拉篩在埃氏篩的基礎上進行優化,達到O(n)的複雜度。
static boolean isprime[];
static int prime[];
static void getprimeoula()// 歐拉篩 {
prime = new int[100001];// 記錄第幾個prime
int index = 0;
isprime = new boolean[1000001];
for (int i = 2; i < 1000001; i++) {
if (!isprime[i]) {
prime[index++] = i;
}
for (int j = 0; j < index && i * prime[j] <= 100000; j++){
isprime[i * prime[j]] = true;//
if (i % prime[j] == 0)
break;
}
}
}
複製代碼
算數分解定理(惟一分解定理):
算數分解定理(惟一分解定理):
任何一個大於1的天然數 N,若是N不爲質數,那麼N能夠惟一分解成有限個質數的乘積 N=P1a1 P2a2P3a3…Pnan,這裏P1<P2<P3…<Pn均爲質數,其中指數ai是正整數。這樣的分解稱爲 N 的標準分解式.
應用:對於一個正整數n,若是n=q1a1 * q2 a2 * …* qnan,那麼他的正因數個數爲(1+a1) * (1+a2)* . . . *(1+an);
1000=2* 500=2* (2 * 250)=2 * 2 *( 2 * 125)=2 * 2 * 2 *(5 * 25)=2 * 2 * 2 * 5 * (5 *5)=23*53.能夠看的出來基本策略就是從2開始除,直到不是2的倍數而後網上遞增求。
計算n的分解方式。主要是經過數的自身對從最小的質數開始整除除一直到不能整除,直到跳出限制條件。
你能夠從2到n;逐個遍歷判斷,知足條件的話就在數組中添加對應的count。固然,每被計算一次的時候,這個數就要被除一次。
上面方法對於大的數據顯然複雜度過高。其實你能夠從2遍歷到根號n+1(i * i<n+1)中止,由於最大的理想乘積是i*i=n,其餘的數據都是一個左,一個右面。最終分解的時候若是都分到這步了說明要麼後面不剩,要麼就是剩一個大質數。
上面雖然從數的量級減小了很多,可是會遍歷不少沒用的合數,好比遍歷過2全部而的倍數都不須要遍歷判斷,因此咱們只須要遍歷素數。素數打表遍歷素數,當遇到多組輸入,數據要求較高的時候,先用素數篩打表,把素數預處理,而後直接從2-素數數組中遍歷便可,由於若是一個數能被拆,那麼他若是不能被拆,他就是素數,若是它還能被拆,那麼它就是合數。因此一個數被分解到最後都是素數的次冪相乘!很重要!這樣可以省的更多的時間。能夠參考素數篩模板。
核心代碼:
不打表:
for(int j=2;j*j<n+1;j++) { while(n%j==0) { n/=j; //根據需求操做 } //根據需求操做... } 複製代碼
打表:
static int index=0;//根據數據範圍範圍內素數的最後一個位置prime[index] long prime[]=new long[100001]; boolean isprime[]=new boolean[1000001]; for(int i=2;i<1000001;i++)//埃拉托色尼篩選法 { if(!isprime[i]) { prime[index++]=i; for(int j=i+i;j<1000000;j=j+i) { isprime[j]=true; } } } ........ ........ // int n; for(int j=0;j<index;j++) { if(n==0||prime[j]>n) {break;}//素數已經超出沒法最大的數,退出 long team=0;//其餘操做,能夠是你本身的邏輯 while(c%prime[j]==0) { c/=prime[j]; team++;//其餘操做 } number*=(1+team);//其餘操做 } 複製代碼
例如給一個1000,這樣的數,問有多少種可能組合使得a * b=1000.或者求a*b中在那個範圍內a,b的排列次數。
首先要了解一個惟一分解定理的應用:對於一個正整數n,若是n=q1a1 * q2 a2 * …* qnan,那麼他的正因數個數爲(1+a1) * (1+a2)…(1+an);對於這個,就能夠衍生其餘問題,好比找兩個因數的組合狀況,可能性,在那個範圍等等。其實這就是一個組合問題。對於每個數有t個,可以影響最終結果的就是這個素數出現的次數。若是細看雖然每一個數的機率都是可能出現和不出現的1/2.可是對於最終結果就是:出現0次,出現1次,出現。。。,出現t次。因此這個數對結果出現的可能行變成了原來次數*(1+t).以此類推,即可獲得全部的因數可能的結果。
就例如1000=23 * 53:
對於結果首先2和5是獨立互不影響的。因此對於一個因數。質數2的搭配有四種,出現0個,1個,2個或3個。同理質數5的搭配也是4種,因此最終因數可能出現的次數是4 * 4=1*(3+1)*(3+1)=16個。
題意:給出n個數,求這n個數中最小的兩個因數乘積,題意有些小的歧義不太好理解。說明白了就是讓你從n個數分解找最小的兩個因子相乘.(1不知足由於1沒有2個及以上因子).
思路:數據量不大,能夠不打表直接素數分解。其實每一個數找到2個因子就能夠中止了,放到list或者數組中,最後排序判斷因子是否大於等於2個。按照要求輸出
附上ac代碼:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class hdu5248 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int T=sc.nextInt();
for(int q=0;q<T;q++)
{
int n=sc.nextInt();
List<Long>list=new ArrayList<Long>();
for(int i=0;i<n;i++)
{
long te=sc.nextLong();
int num=0;
for(int j=2;(long)j*j<te+1;j++)
{
while(te%j==0)
{
list.add((long) j);
te/=j;
num++;
}
if(num>2)break;//其實找到兩個就不用找了
}
if(te>1) {list.add(te);}
}
if(list.size()<2)
System.out.println(-1);
else {
list.sort(null);
System.out.println((long)(list.get(0)*list.get(1)));
}
}
}
}
複製代碼
lightoj1341 題目大意:給個面積s。一個邊b,問最小邊大於b的全部可能狀況。 思路:總體-多餘。先求出全部的排列次數,而後除以二(要求組合隊數)。再從0頭到b開始剪掉多餘的狀況。不須要考慮特大的那邊,由於是對稱的已經除以過二了。 ac代碼:
埃氏篩
import java.util.Scanner;
public class testC {
static int index=0;
public static void main(String[] args) {
// TODO 自動生成的方法存根
long prime[]=new long[100001];
boolean isprime[]=new boolean[1000001];
for(int i=2;i<1000001;i++)//埃拉托色尼篩選法
{
if(!isprime[i])
{
prime[index++]=i;
for(int j=i+i;j<1000000;j=j+i)
{
isprime[j]=true;
}
}
}
Scanner sc=new Scanner(System.in);
int t=sc.nextInt();
for(int i=0;i<t;i++)
{
long a=sc.nextLong();
long b=sc.nextLong();
long number=1;
long c=a;
if(b*b>=a) {number=0;}//不可能的狀況,最小邊大於可能拼成的狀況
else {
for(int j=0;j<index;j++)
{
if(c==0||prime[j]>c) {break;}//超出界,跳出
long team=0;
while(c%prime[j]==0)
{
c/=prime[j];team++;
}
number*=(1+team);//計算
}
if(c>1)number*=2;
number/=2;
//這裏別被繞進去。這裏不是按照次冪計算的,而是按照實打實的一個一個數判斷的。
for(int j=1;j<b;j++)
{
if(a%j==0)number--;
}
}
System.out.println("Case "+(i+1)+": "+number);
}
}
}
複製代碼
歐拉篩:
import java.util.Scanner;
public class testC {
static int index=0;
public static void main(String[] args) {
// TODO 自動生成的方法存根
int prime[] = new int[100001];// 記錄第幾個prime
int index = 0;
boolean isprime[] = new boolean[1000001];
for (int i = 2; i < 1000001; i++) {
if (!isprime[i]) {
prime[index++] = i;
}
for (int j = 0; j < index && i * prime[j] < 1000001; j++) {
isprime[i * prime[j]] = true;// 找到的素數的倍數不訪問
if (i % prime[j] == 0)
break;// 關鍵!!!!
}
}
Scanner sc=new Scanner(System.in);
int t=sc.nextInt();
for(int i=0;i<t;i++)
{
long a=sc.nextLong();
long b=sc.nextLong();
long number=1;
long c=a;
if(b*b>=a) {number=0;}//不可能的狀況,最小邊大於可能拼成的狀況
else {
for(int j=0;j<index;j++)
{
if(c==0||prime[j]>c) {break;}
long team=0;
while(c%prime[j]==0)
{
c/=prime[j];team++;
}
number*=(1+team);
}
if(c>1)number*=2;
number/=2;
for(int j=1;j<b;j++)
{
if(a%j==0)number--;
}
}
System.out.println("Case "+(i+1)+": "+number);
}
}
}
複製代碼
求歐拉函數代碼的方式:直接求和打表 歐拉函數的做用:一個數n,求小於n的互質的個數。特例:1——oula(1)=1; 歐拉函數的公式:
那麼我難道須要一個個循環比較嗎?
答案先然不可能,由於若是數值過大這是個很大的複雜度。那麼我該如何處理?
換一種思惟。好比求24中的互質個數。答案是1,5,7,11,13,17,19,23。共8個
附上直接求代碼:
private static int oula(int team) {
int i=0;int res=team;int team1=team;
for(i=2;i<(int)Math.sqrt(team1)+1;i++)
{
if(team%i==0) {
res=res/i*(i-1);
while(team%i==0) {team/=i;}//保證沒有i做爲因子
}
}
if(team>1)res=res/team*(team-1);//說明後面還有一個比較大的互質因數大小爲team
return res;
}
複製代碼
其中,res爲結果,team1做爲求因數用。若是實在不能理解,好好看下質因數分解。
打表代碼:
int a[]=new int[1000001];
for(int i=1;i<1000001;i++)
{
a[i]=i;
}
for(int i=2;i+2<1000001;i+=2)
{
a[i]/=2;
}
for(int i=3;i+2<1000001;i+=2)
{
if(a[i]==i)
{
for(int j=i;j+i<=1000001;j+=i)
{
a[j]=a[j]/i*(i-1);
}
}
}
複製代碼
Bamboo Pole-vault是Xzhiland的一項大受歡迎的運動。 Phi-shoe大師是他成功的很是受歡迎的教練。他須要爲他的學生提供一些竹子,因此他讓他的助手Bi-Shoe去市場購買。市場上有不少可能的整數長度的Bamboos(是的!)。根據Xzhila的傳統,
竹子的分數=Φ(竹子的長度)
(Xzhilans很是喜歡數論)。對於您的信息,Φ(n)=小於n的數字,它們相對於素數(除了1以外沒有公約數)到n。所以,長度爲9的竹子的得分爲6,由於1,2,4,5,7,8是9的相對素數。
助理雙鞋必須爲每一個學生買一個竹子。做爲一個扭曲,Phi-shoe的每一個撐杆跳學生都有一個幸運數字。 Bi-shoe但願購買竹子,這樣他們每一個人都會獲得一張分數大於或等於他/她的幸運數字的竹子。 Bi-shoe但願最大限度地減小購買竹子所花費的總金額。一個竹子單位花費1 Xukha。幫助他
輸入 輸入以整數T(≤100)開始,表示測試用例的數量。
每一個案例都以包含整數n(1≤n≤10000)的行開頭,表示Phi-shoe的學生人數。下一行包含n個空格分隔的整數,表示學生的幸運數字。每一個幸運數字將位於[1,106]範圍內。
輸出 對於每種狀況,打印案例編號和購買竹子所花費的最少金額。有關詳細信息,請參閱示例 Sample Input 3 5 1 2 3 4 5 6 10 11 12 13 14 15 2 1 1 Sample Output Case 1: 22 Xukha Case 2: 88 Xukha Case 3: 4 Xukha
題意:給你n個整數,第i個整數爲Xi。定義phi(k)爲k的歐拉函數值,設pi爲知足phi(pi)>=Xi的最小整數,題目就是要求sum(p1,p2,p3,...,pn)。
告訴你幸運數字x,你找出phi(n)=x的這個最小的n,若干個這樣數的合。
首先要清楚幾個概念phi(n)=n-1,==n爲素數==時候。由於n和小於它的任意都互質。 因此解題思路大體有兩個:
歐拉是最明顯的,要找出大於這個數最小的那個phi[i],若是==單個歐拉函數求會TL==因此須要歐拉打表。沒輸入一個數網上找幾個就好了
n爲素數時候,phi(n)=n-1,因此第一個phi(i)=t的那個i就是在t右側的第一個素數。有了這個思路你就能夠用素數解決問題,能夠用素數篩。用直接的素數斷定也能過。 c++代碼: 直接斷定
#include <iostream>
#include<stdio.h>
using namespace std;
#define ll long long
bool isprime(int index) {
if(index<=2)return true;
else {
for(int i=2;i*i<index+1;i++)
{
if(index%i==0)return false;
}
return true;
}
}
int main() {
int t;cin>>t;
for(int i=0;i<t;i++)
{
int n;cin>>n;ll count=0;
for(int j=0;j<n;j++)
{
ll team;
cin>>team;
int index=team+1;
while(!isprime(index))
{index++;}
count+=index;
}
//string s=" Xukha";
printf("Case %d: %lld Xukha\n",(i+1),count);
}
return 0;
}
複製代碼
歐拉篩
#include <iostream>
#include<stdio.h>
using namespace std;
#define ll long long
const int MAXN=1100000+7;
int m;
ll a[MAXN],euler[MAXN];
void phi() {
for(int i=1;i<=m;i++)
a[i]=i;
for(int i=2;i<=m;i+=2)
a[i]>>=1;
for(int i=3;i<=m;i++)
{
if(a[i]==i)
{
for(int j=i;j<=m;j+=i)
a[j]=(a[j]/i)*(i-1);
}
}
}
int main() {
m=1100000;
phi();
int t;cin>>t;
for(int i=0;i<t;i++)
{
ll n,count;
cin>>n;count=0;
for(int j=0;j<n;j++)
{
ll team;
cin>>team;
int index=team+1;
while(a[index]<team)
{index++;}
count+=index;
}
printf("Case %d: %lld Xukha\n",(i+1),count);
}
return 0;
}
複製代碼
java 歐拉打表(能夠本身改爲素數)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Scanner;
public class Main{
public static void main(String[] args) throws IOException {
// TODO 自動生成的方法存根
StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
in.nextToken();int t=(int)in.nval;
int a[]=new int[1100001];
for(int i=1;i<1100001;i++)
{
a[i]=i;
}
for(int i=2;i+2<1100001;i+=2)
{
a[i]/=2;
}
for(int i=3;i+2<1100001;i+=2)
{
if(a[i]==i)
{
for(int j=i;j+i<=1100001;j+=i)
{
a[j]=a[j]/i*(i-1);
}
}
}
for(int i=0;i<t;i++)
{
in.nextToken();int n=(int)in.nval;long count=0;
for(int j=0;j<n;j++)
{
in.nextToken();
long team=(long)in.nval;
int index=(int) (team+1);
while(a[index]<team) {index++;}
count+=index;
//System.out.println(oula(team));
}
System.out.println("Case "+(i+1)+": "+count+" Xukha");
}
}
private static boolean isprime(int index) {
if(index<=2)return true;
else {
for(int i=2;i*i<index+1;i++)
{
if(index%i==0)return false;
}
return true;
}
}
private static int oula(int team) {
int i=0;int res=team;int team1=team;
for(i=2;i<(int)Math.sqrt(team1)+1;i++)
{
if(team%i==0) {
res=res/i*(i-1);
while(team%i==0) {team/=i;}//保證I是素數
}
}
if(team>1)res=res/team*(team-1);
return res;
}
}
複製代碼
我的公衆號:bigsai