數學渣的自我修養!!!

之零:c++

這一篇都是水題,不過仍是有幾道被卡了一下,仍是總結一下。ide

A題:spa

 給定a和b的gcd和lcm,求一組知足的a,b,且a最小。3d

顯然,a,b必然是gcd的倍數,是lcm的約數,若是gcd不是lcm的約數則無解,不然,要使a最小,a只能是gcd,又由於b是gcd的倍數,那麼b就只能是a的倍數,也就只能是a和b的最小公倍數lcm,因此答案就是a=gcd,b=lcm。code

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll G,L;

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T--){
        scanf("%lld%lld",&G,&L);
        if(L%G==0) printf("%lld %lld\n",G,L);
        else puts("-1");
    }
    return 0;
}
View Code

B題:blog

給定A,C,且LCM(A,B)=C,求知足等式的最小的B。ci

由於lcm=...p^k=...p^max(k1,k2),對C和A分別質因數分解,要使B最小,那麼若是某個質因數p在C中出現的次數大於A的次數,那麼B必須去C的次數,不然不取該質因數。get

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll a,b,c;
bool isprime[maxn];
vector<int> prime;

void getPrime()
{
    memset(isprime,1,sizeof(isprime));
    isprime[1]=0;
    REP(i,2,maxn-1){
        if(!isprime[i]) continue;
        for(int j=i+i;j<maxn;j+=i) isprime[j]=0;
    }
    REP(i,2,maxn-1) if(isprime[i]) prime.push_back(i);
}

ll qpow(ll n,ll k)
{
    ll res=1;
    while(k){
        if(k&1) res*=n;
        n*=n;
        k>>=1;
    }
    return res;
}

ll solve()
{
    ll res=1;
    ll A=a,C=c;
    for(int i=0;i<prime.size();i++){
        ll t=prime[i];
        if(t*t>C) break;
        int cntA=0,cntC=0;
        while(A%t==0) cntA++,A/=t;
        while(C%t==0) cntC++,C/=t;
        if(cntA<cntC) res*=qpow(t,cntC);
    }
    if(C!=1&&A==1) res*=C;
    return res;
}

int main()
{
    //freopen("in.txt","r",stdin);
    getPrime();
    int T;cin>>T;
    while(T--){
        scanf("%lld%lld",&a,&c);
        if(c%a) puts("NO SOLUTION");
        else printf("%lld\n",solve());
    }
    return 0;
}
View Code

C題:it

把一個數N分紅k個數的和,問方案數。event

問題等價於x1+x2+...+xk=N. (0<=xi<=N).

另y=x+1,則y1+y2+...+yk=N+k,而後隔板便可獲得C(N+k-1,k-1)。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll n,k;
ll C[1200][1200];

void Init()
{
    C[0][0]=1;
    REP(i,1,1100){
        REP(j,0,i){
            if(j==0) C[i][j]=C[i-1][j];
            else C[i][j]=(C[i-1][j]+C[i-1][j-1])%1000000;
        }
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    Init();
    while(~scanf("%lld%lld",&n,&k)){
        if(n==0&&k==0) break;
        printf("%lld\n",C[n+k-1][k-1]);
    }
    return 0;
}
View Code

D題:

找最大的k使 m^k能整除n!。

對n!和m進行質因數分解,記下每一個質因數的次數。二分k,判斷m^k可否整除n!,能整除的條件是全部質因數都知足次數大於等於另外一個,k次方只要將次數乘以k便可。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll p1[maxn],cnt1[maxn];
ll p2[maxn],cnt2[maxn];
int pn;
ll n,m;

vector<int> prime;
bool isprime[maxn];

void getPrime()
{
    memset(isprime,1,sizeof(isprime));
    isprime[1]=0;
    REP(i,2,maxn-1){
        if(!isprime[i]) continue;
        for(int j=i+i;j<maxn;j+=i) isprime[j]=0;
    }
    REP(i,2,maxn-1) if(isprime[i]) prime.push_back(i);
}

void get(ll n,ll m)
{
    pn=0;
    for(int i=0;i<prime.size();i++){
        ll t=prime[i];
        if(t>10000) break;
        p1[++pn]=t;cnt1[pn]=0;
        p2[pn]=t;cnt2[pn]=0;
        while(m%t==0) cnt2[pn]++,m/=t;
    }
    REP(i,1,n){
        ll x=i;
        REP(j,1,pn){
            ll t=p1[j];
            if(t>x) break;
            while(x%t==0) cnt1[j]++,x/=t;
        }
    }
}

bool check(ll k)
{
    REP(i,1,pn){
        if(cnt1[i]<cnt2[i]*k) return 0;
    }
    return 1;
}

ll bin(ll l,ll r)
{
    ll res=-1;
    while(l<=r){
        ll m=(l+r)>>1;
        if(check(m)) l=m+1,res=m;
        else r=m-1;
    }
    return res;
}

void solve()
{
    ll ans=bin(1,INF);
    if(ans==-1) puts("Impossible to divide");
    else printf("%lld\n",ans);
}

int main()
{
    //freopen("in.txt","r",stdin);
    getPrime();
    int T;cin>>T;int casen=1;
    while(T--){
        scanf("%lld%lld",&m,&n);
        get(n,m);
        printf("Case %d:\n",casen++);
        solve();
    }
    return 0;
}
View Code

E題:

求有多少對(a,b)知足lcm(a,b)=n,a<=b。

對n進行質因數分解,因爲lcm=...p^k=p^max(ka,kb),因此每一個質因子的方案數就是2*(k+1)-1,而後乘法原理連乘,獲得cnt,但這會多算a>b的,因此答案就是(cnt-1)/2+1,1是a=b的狀況。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll n;
ll p[maxn],pn;
ll cnt[maxn];
vector<int> prime;
bool isprime[maxn];

void getPrime()
{
    memset(isprime,1,sizeof(isprime));
    isprime[1]=0;
    REP(i,2,maxn-1){
        if(!isprime[i]) continue;
        for(int j=i+i;j<maxn;j+=i) isprime[j]=0;
    }
    REP(i,2,maxn-1) if(isprime[i]) prime.push_back(i);
}

void get(ll n)
{
    pn=0;
    for(int i=0;i<prime.size();i++){
        ll t=prime[i];
        if(t*t>n) break;
        if(n%t==0){
            p[++pn]=t;cnt[pn]=0;
            while(n%t==0) cnt[pn]++,n/=t;
        }
    }
    if(n!=1) p[++pn]=n,cnt[pn]=1;
}

ll solve()
{
    get(n);
    ll res=1;
    REP(i,1,pn) res*=(2*(cnt[i]+1)-1);
    return (res+1)/2;
}

int main()
{
    //freopen("in.txt","r",stdin);
    getPrime();
    while(~scanf("%lld",&n)&&n){
        printf("%lld %lld\n",n,solve());
    }
    return 0;
}
View Code

F題:

打印1~2^64-1範圍內的超級冪(即知足是兩個數以上的冪的數).

顯然,超級冪等價於某個數的合數次冪,冪次的最大值確定在64之內,因此只須要找出64以內的合數,最小的合數是4,因此底數最大是2^16,枚舉便可,用取對數轉double判斷是否超過2^64-1。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef unsigned long long ll;
const int maxn=1000100;
const int INF=1e9+10;
const double EPS=1e-10;

vector<int> prime;
bool isprime[maxn];

void getPrime()
{
    memset(isprime,1,sizeof(isprime));
    isprime[1]=0;
    REP(i,2,maxn-1){
        if(!isprime[i]) continue;
        for(int j=i+i;j<maxn;j+=i) isprime[j]=0;
    }
    REP(i,2,maxn-1) if(isprime[i]) prime.push_back(i);
}

set<ll> ans;

void work(ll p)
{
    ll cur=p;
    REP(i,2,65){
        if(1.0*cur*p>pow(2.0,64.0)-1.0+EPS) return;
        ll t=cur*p;
        if(t/p!=cur) return;
        cur*=p;
        if(cur<=0) return;
        if(isprime[i]) continue;
        ans.insert(cur);
    }
}

void solve()
{
    ans.clear();
    REP(i,2,(1LL<<16)) work(i);
}

int main()
{
    //freopen("in.txt","r",stdin);
    getPrime();
    solve();
    printf("1\n");
    for(set<ll>::iterator it=ans.begin();it!=ans.end();++it) printf("%llu\n",*it);
    //cout<<(int)ans.size()<<endl;
    return 0;
}
View Code

G題:

求一個數列的全部排列組成的n位數的和。

顯然每一位的和都是同樣的,容易算出排列的個數爲Cnt=n!/(cnt1!*cnt2!*...*cntk!) ,那麼每一位的數的和就是Cnt*序列平均數=Cnt*sum/n。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef unsigned long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n;
ll a[maxn];
ll fac[maxn];
map<ll,ll> cnt;

void Init()
{
    fac[0]=1;
    REP(i,1,12) fac[i]=fac[i-1]*i;
}

int main()
{
    //freopen("in.txt","r",stdin);
    Init();
    while(~scanf("%d",&n)&&n){
        ll s=0;cnt.clear();
        REP(i,1,n) scanf("%llu",&a[i]),s+=a[i],cnt[a[i]]++;
        ll Cnt=fac[n];
        for(map<ll,ll>::iterator it=cnt.begin();it!=cnt.end();++it) Cnt/=fac[it->second];
        s*=Cnt;
        s/=n;
        ll res=0;
        REP(i,1,n) res=res*10+s;
        printf("%llu\n",res);
    }
    return 0;
}
View Code

H題:

求n我的,去k我的組成一隻隊伍,並從k我的中選一個隊長的方案數(1<=k<=n),k能夠任取,沒有給定。

顯然答案等於C(n,1)*1+C(n,2)*2+...+C(n,n)*n.

k*C(n,k)=k*n!/(k!*(n-k)!)=n*(n-1)!/((k-1)!*((n-1)-(k-1))!)=n*C(n-1,k-1).

則C(n,1)*1+C(n,2)*2+...+C(n,n)*n= n*( C(n-1,0)+C(n-1,1)+...+C(n-1,n-1)) = n*(2^(n-1) -1) .

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef unsigned long long ll;
const int maxn=1000100;
const int INF=1e9+10;

const ll MOD=1e9+7;
ll n;

ll qpow(ll n,ll k,ll p)
{
    ll res=1;
    while(k){
        if(k&1) res=(res*n)%p;
        n=(n*n)%p;
        k>>=1;
    }
    return res;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;int casen=1;
    while(T--){
        scanf("%lld",&n);
        printf("Case #%d: %lld\n",casen++,(n*qpow(2,n-1,MOD))%MOD);
    }
    return 0;
}
View Code

I題:

求第n個迴文數。

很容易算出長度爲len的迴文數的個數爲f(len).

先肯定第n個迴文數的長度,而後保證首位大於0,按字典序逐個放置便可。

確實是略麻煩,須要細心一點。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll n;
int ans[maxn];

ll qpow(ll n,ll k)
{
    ll res=1;
    while(k){
        if(k&1) res*=n;
        n*=n;
        k>>=1;
    }
    return res;
}

ll Cnt(int len)
{
    if(len==0) return 0;
    if(len%2==0) return qpow(10,len/2-1)*9;
    else return qpow(10,len/2)*9;
}

void solve(ll n)
{
    int len;
    REP(i,1,20){
        ll t=Cnt(i);
        if(t>=n){
            len=i;break;
        }
        n-=t;
    }
    if(len%2==0){
        if(len==2) ans[1]=ans[2]=n;
        else{
            ans[1]=(n-1)/qpow(10,len/2-1)+1;
            n=(n-1)%qpow(10,len/2-1);
            for(int i=len/2;i>=2;i--) ans[i]=n%10,n/=10;
            REP(i,len/2+1,len) ans[i]=ans[len+1-i];
        }
    }
    else{
        if(len==1) ans[1]=n;
        else{
            ans[1]=(n-1)/qpow(10,len/2)+1;
            n=(n-1)%qpow(10,len/2);
            for(int i=len/2+1;i>=2;i--) ans[i]=n%10,n/=10;
            REP(i,len/2+1,len) ans[i]=ans[len+1-i];
        }
    }
    REP(i,1,len) printf("%d",ans[i]);puts("");
}

void test()
{
    REP(i,1,300) solve(i);
}

int main()
{
    //freopen("in.txt","r",stdin);
    //test();return 0;
    while(~scanf("%lld",&n)&&n){
        solve(n);
    }
    return 0;
}
View Code

J題:

給一堆數,A,B輪流操做,每次操做任取走一個數,使剩下的數的和能被3整除,不能操做者爲輸,判斷勝者。

直接取走一個%3=k的數和取走另外一個一樣%3=k的數是等價的,模擬便可。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int cnt[3];
char s[maxn];
int len;

bool dfs(int len,int sum,int x,int y,int z)
{
    if(len==1) return 1;
    if(sum==0){
        if(x>0) return !dfs(len-1,0,x-1,y,z);
        return 0;
    }
    if(sum==1){
        if(y>0) return !dfs(len-1,0,x,y-1,z);
        return 0;
    }
    if(sum==2){
        if(z>0) return !dfs(len-1,0,x,y,z-1);
        return 0;
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;int casen=1;
    while(T--){
        printf("Case %d: ",casen++);
        scanf("%s",s+1);
        len=strlen(s+1);
        MS0(cnt);
        int sum=0;
        REP(i,1,len) cnt[(s[i]-'0')%3]++,sum+=s[i]-'0';
        if(dfs(len,sum%3,cnt[0],cnt[1],cnt[2])) puts("S");
        else puts("T");
    }
    return 0;
}
View Code

K題:

把一個數N分解成幾個數的lcm,使LCM(a1,a2,...,ak)=N,求最小的a1+a2+...+ak.

顯然分解成不互質且每一個ai儘可能小就好,那麼質因數分解便可,答案就是ans=p1^k1+p2^k2+...+pm^km.

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll n;
vector<int> prime;
bool isprime[maxn];

void getPrime()
{
    memset(isprime,1,sizeof(isprime));
    isprime[1]=0;
    REP(i,2,maxn-1){
        if(!isprime[i]) continue;
        for(int j=i+i;j<maxn;j+=i) isprime[j]=0;
    }
    REP(i,2,maxn-1) if(isprime[i]) prime.push_back(i);
}

ll qpow(ll n,ll k)
{
    ll res=1;
    while(k){
        if(k&1) res*=n;
        n*=n;
        k>>=1;
    }
    return res;
}

ll solve()
{
    if(n==1) return 2;
    ll pn=0;
    ll res=0;
    for(int i=0;i<prime.size();i++){
        ll t=prime[i];
        if(t*t>n) break;
        if(n%t==0){
            ll cnt=0;
            while(n%t==0) n/=t,cnt++;
            res+=qpow(t,cnt);
            pn++;
        }
    }
    if(n!=1){
        res+=n;
        pn++;
    }
    if(pn==1) res++;
    return res;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int casen=1;getPrime();
    while(~scanf("%lld",&n)&&n){
        printf("Case %d: ",casen++);
        printf("%lld\n",solve());
    }
    return 0;
}
View Code

L題:

求a和b之間的平方數個數1<=a<=b<=1e6,範圍比較小,暴力便可,水題。

若是範圍1e18的話,可能數位dp可解。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int L,R;

int F(int n)
{
    int res=0;
    REP(i,1,n){
        if(i*i>n) break;
        res++;
    }
    return res;
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&L,&R)){
        if(L==0&&R==0) break;
        printf("%d\n",F(R)-F(L-1));
    }
    return 0;
}
View Code
相關文章
相關標籤/搜索