暑期MQFMATH训练营2

Multiply

题目链接

计蒜客 42544

题意

\(Z=a_1!*a_2!*.....*a_n!\)
\(b_i=Z*X^i\)
\(b_i是Y!的一个因子\)
给定n,X,Y的情况下,问i最多能有多大

题解

第一时间想到的就是质因数分解,然后根据质因数的个数去计算,emm.....然后就tle了
这道题求的是i,i是X的幂次,又和Z有关,很容易看出作为多个阶乘的乘积是不能算出来的,所以分解成质因数就成了最好的方法
因为\(b_i是Y!\)的因子,所以把\(Yi\)也分解成质因子的乘积,然后答案就很明显了
对于任意\(Y_i的因子y_i,在Y中有y个,在Z中有z个,在X中有x个,那么i最大就是(y-z)/x了\)
PS:因为数据量很大,所以得用pollard_rho算法,不然会tle

AC代码


#include "bits/stdc++.h"

using namespace  std;
#define int long long
#define ll long long
const int maxn=2e6+10;
const int inf=0x3f3f3f3f;
const int INF=1ll<<62;
inline int rd()
{
    int a;scanf("%lld",&a);return a;
}

int t,n,a[maxn],x,y;
int c1[maxn],c2[maxn],c3[maxn];
int prime[maxn],prime2[maxn],cnt=0,s=0,vis[maxn];


ll gcd(ll a, ll b) {
    return b ? gcd(b, a % b) : a;
}

ll quick_mult(ll a, ll b, ll mod) {
    ll ans = 0;
    while(b) {
        if(b & 1) ans = (ans + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return ans;
}
ll quick_pow(ll a, ll n, ll mod) {
    ll ans = 1;
    while(n) {
        if(n & 1) ans = quick_mult(ans, a, mod);
        a = quick_mult(a, a, mod);
        n >>= 1;
    }
    return ans;
}
bool miller_rabin(ll n) {
    if(n == 2) return true;
    if(n < 2 || !(n & 1)) return false;
    ll s = 0, d = n - 1;
    while(!(d & 1)) {
        d >>= 1;
        s++;
    }
    for(int i = 1; i <= 11; i++) {
        ll a = rand() % (n - 2) + 2;
        ll now = quick_pow(a, d, n), pre = now;
        for(int j = 1; j <= s; j++) {
            now = quick_mult(now, now, n);
            if(now == 1 && pre != 1 && pre != n - 1) return false;
            pre = now;
        }
        if(now != 1) return false;
    }
    return true;
}
ll pollard_rho(ll n, int c) {
    ll x, y, i = 1, k = 2;
    x = y = rand() % (n - 2) + 2;
    for( ; ; ) {
        i++;
        x = (quick_mult(x, x, n) + c) % n;
        ll g = gcd(y - x, n);
        if(g > 1 && g < n) return g;
        if(x == y) return n;
        if(i == k) y = x, k <<= 1;
    }
}
void find_fac(ll n, int k) {
    if(n == 1) return ;
    if(miller_rabin(n)) {
        prime[++s]=n;
        return ;
    }
    ll p = n;
    int c = k;
    while(p >= n) p = pollard_rho(p, c--);
    find_fac(p, k);
    find_fac(n / p, k);
}

void init(){
    prime2[++cnt]=prime[1];
    c3[cnt]=1;
    for(int i=2;i<=s;i++){
        if(prime[i]==prime[i-1])c3[cnt]++;
        else prime2[++cnt]=prime[i],c3[cnt]=1;
    }
}

ll cal(ll n,ll x){
    ll ans=0;
    while(n){
        ans+=n/x;
        n/=x;
    }
    return ans;
}

signed main(){
    srand((unsigned)time(NULL));
    t=rd();
    while(t--){
        s=0;cnt=0;
        n=rd();x=rd();y=rd();
        find_fac(x,1111);
        sort(prime+1,prime+1+s);
        init();
        for(int i=1;i<=n;i++){
            a[i]=rd();
        }
        ll ans=4e18;
        for(int i=1;i<=cnt;i++){
            ll num=0;
            for(int j=1;j<=n;j++){
                num+=cal(a[j],prime2[i]);
            }
            ll t=cal(y,prime2[i])-num;
            if(t<0)t=0;
            ans=min(ans,t/c3[i]);
        }
        printf("%lld\n",ans);
        for(int i=1;i<=cnt;i++)c3[i]=0;
    }
    return 0;
}

A - Simple Math 2

题目链接

arc111_a

题意

求给定N,M的情况下\(\lfloor\frac{10^N}{M}\rfloor\)%M的值

题解

\(\lfloor\frac{10^N}{M}\rfloor\)%M
\(=>\lfloor\frac{10^N}{M}-k*M\rfloor\)%M
\(=>\lfloor\frac{10^N-k*M^2}{M}\rfloor\)%M
\(=>\lfloor\frac{10^NmodM^2}{M}\rfloor\)%M
\(10^NmodM^2可以直接用ksm求\)

AC代码

#include "bits/stdc++.h"
using namespace  std;
#define int long long
#define ll long long
const int maxn=2e6+10;
const int inf=0x3f3f3f3f;
const int INF=1ll<<62;
const int mod=1e9+7;

inline int rd()
{
    int a;scanf("%lld",&a);return a;
}

int n,m;
int ksm(int a,int b=mod-2,int m=mod){
    int res=1;
    while(b){
        if(b&1){
            res*=a;
            res%=m;
        }
        a*=a;
        a%=m;
        b>>=1;
    }
    return res;
}

signed main(){
    n=rd();m=rd();
    cout<<ksm(10,n,m*m)/m%m<<endl;
    return 0;
}



Problem J. Prime Game

题目链接

Gym - 101981J

题意

\(设 mul(l,r)=\prod_{i=l}^ra_i和fac(l,r)=mul(l,r)不同素因子的数量\)
给一个数组a,求\(\sum_{i=1}^n\sum_{j=i}^nfac(i,j)\)

题解

计算出来每个数的质因子在各个区间的贡献。
以第二个例子为例,第一个元素6的素因子2在[1,1][1,2],.....,[1,10]10个区间有贡献,所以总和加10
第一个元素6的素因子3在[1,1][1,2],.....,[1,10]10个区间有贡献,所以总和加10
而像第五个元素中素因子5的计算就需要去掉前面的5已经贡献的区间
所以第二个样例总的\(sum = 10+10+9*2+8*3+7+6*4+5*5+4+0+2*4+1+3=134\)
所以通项式\(sum_i=(n-prime[i][pos]+1)*(prime[i][pos]-prime[i][pos-1])\)

AC代码

#include "bits/stdc++.h"
using namespace  std;
//#define int long long
#define ll long long
const int maxn=1e6+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

inline int rd()
{
    int a;scanf("%d",&a);return a;
}

int n,m;
int vis[maxn],prime[maxn],s=0;
vector<ll>ve[maxn];//这里没开ll,wa7

void init(){
    for(int i=2;i*i<=1000010;i++) {
        if(!vis[i]){
            vis[i]=i;prime[++s]=i;
        }
        for(int j=1;j<=s;j++){
            if(vis[i]<prime[j]||prime[j]*i>1010)break;
            vis[prime[j]*i]=prime[j];
        }
    }
}

void js(int n,int pos){
    int tmp=n;
    for(int i=1;i<=s&&prime[i]<=n;i++){
        if(tmp%prime[i]==0) {
            ve[prime[i]].push_back(pos);
        }
        while(tmp%prime[i]==0)tmp/=prime[i];
    }
    if(tmp!=1){
        if(!ve[tmp].size()){
            prime[++s]=tmp;
        }
        ve[tmp].push_back(pos);
    }
}

signed main(){
    init();
    n=rd();
    for(int i=1;i<=n;i++){
        int aa=rd();js(aa,i);
    }
    ll ans=0;
    for(int i=1;i<=s;i++){
        for(int j=0;j<ve[prime[i]].size();j++){
            if(j!=0)ans+=(n-ve[prime[i]][j]+1)*(ve[prime[i]][j]-ve[prime[i]][j-1]);
            else ans+=(n-ve[prime[i]][j]+1)*(ve[prime[i]][j]);
        }
    }
    printf("%lld\n",ans);
    return 0;
}

//10+10+9*2+8*3+7+6*4+5*5+4+0+2*4+1+3=134
//ans=(n-prime[i][pos]+1)*(prime[i][pos]-prime[i][pos?1])

C. Berland Regional

题目链接

Codeforces1519C

题意

有n个球员,每个球员都有属于自己的大学,属于自己的能力值,同一个大学的队员可以组队,人数不够则无法组队,问当队伍人数要求为k时,所有大学的队员能力数最多是多少?

题解

如题,直接暴力,每次放能力值最大的进去就好了,人数不够就不算

AC代码

#include "bits/stdc++.h"
using namespace  std;
#define int long long
#define ll long long
const int maxn=1e6+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

inline int rd()
{
    int a;scanf("%lld",&a);return a;
}

int cmp(int a,int b){
    return a>b;
}

signed main(){
    ll t=rd();
    while(t--){
        ll n=rd();
        map<ll, vector<ll>> mp;
        vector<ll>a(n+1),sum(n+1);
        for(int i=1;i<=n;i++)a[i]=rd();
        for(int i=1;i<=n;i++) {
            ll aa = rd();
            mp[a[i]].push_back(aa);
        }
        for(auto it : mp ) {
            sort(it.second.begin(), it.second.end(), cmp);
            int len = it.second.size();
            vector<ll>b(len+1);
            for (int i = 1; i <= len; i++) {
                b[i] = b[i - 1] + it.second[i-1];
            }
            for (int i = 1; i <= len; i++) {
                sum[i] = sum[i] + b[len - len % i];
            }
        }
        for(int i=1;i<=n;i++){
            printf("%lld%c",sum[i],i==n?'\n':' ');
        }
    }
    return 0;
}

D. Nezzar and Board

题目链接

Codeforces 1478D

题意

给一串数组x,可以选择其中两个进行2x-y操做,问能不能变成想要的数字k

题解

最终答案的形式必定为\(2x-y=x+(x-y)=k\)
即一个数加上另一个数和其本身的差值的和
也就是\(a_i+\sum_{i,k}(a_j-a_k)\)
\(\sum_{i,k}(a_j-a_k)=\sum_{i=2}^nf_i(a_i-a_{i-1}),f_i为系数\)
\(g=gcd([a_i-a_{i-1}]),i\epsilon[2,n]\)
从裴蜀定理可知\(\sum_{i=2}^nf_i(a_i-a_{i-1})\)%\(g=0\)
因此只要判断\((k-a_i)\)%\(g==0\)
因为后面的数都可以用\(a_1+\sum(a_j-a_{j-1})\)得到
所以只要判断\((k-a_1)\)%\(g==0\)

AC代码

#include "bits/stdc++.h"
using namespace  std;
#define int long long
#define ll long long
const int maxn=2e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

inline int rd()
{
    int a;scanf("%lld",&a);return a;
}
inline int gcd(int a,int b){
    return !b? a:gcd(b,a%b);
}

int t;
int n,m;
int a[maxn];
signed main(){
    t=rd();
    while(t--){
        n=rd();m=rd();
        for(int i=1;i<=n;i++){
            a[i]=rd();
        }
        int gcdd=0;
        for(int i=2;i<=n;i++){
            gcdd=gcd(a[i]-a[i-1],gcdd);
        }
        if((m-a[1])%gcdd==0)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
posted @ 2021-07-14 21:15  碳素油墨  阅读(66)  评论(0)    收藏  举报