• [UOJ摸鱼]UOJ Round #1解题报告(未完)


    [UOJ摸鱼]UOJ Round #1解题报告

    前言

    还有好多题没补,先摸会儿鱼~

    缩进优化

    链接

    http://uoj.ac/problem/21

    题解

    先推柿子!
    要算的是找一个(K)使得(sum_{i=1}^{n}{lfloor frac{a_n}{K} floor + a_n mod K})最小
    化简一下就是(sum_{i-1}^{n}{a_i - (K-1) imes lfloor frac{a_n}{K} floor})
    显然(K)应该满足(1leq K leq max(a_i))
    当我们确定一个(K)的时候,(1)(max(a_i))内最多有(lfloor frac{max(a_i)}{K} floor)个不同的(lfloor frac{x}{K} floor)的值。
    于是我们直接枚举(K),算出所有可能答案取个min就行。效率是(O(max(a_i)log(max(a_i))))

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const LL P=998244353;
    const int N=1e6+10;
    int n;
    LL a[N],c[N];
    LL ans,sum,mx,res,now; 
    int main(){
        scanf("%d",&n);sum=0;mx=0;
        for(int i=1;i<=n;++i) {
            scanf("%lld",&a[i]);
            sum+=a[i];mx=max(mx,a[i]);++c[a[i]];
        }
        for(int i=1;i<=mx;++i) c[i]+=c[i-1];
        ans=sum;
        for(LL k=2;k<=mx;++k){
            now=0;
            for(LL l=k,r=k+k-1;l<=mx;l+=k,r+=k){
                r=min(r,mx);
                now+=(c[r]-c[l-1])*(l/k);
            }
            now=now*(k-1);
            res=sum-now;
            ans=min(ans,res);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    外星人

    链接

    http://uoj.ac/problem/22

    题解

    首先可以发现我们对一个数取模多次相当于一次。。一个数对比它大的数取模不变。
    第一步一定是排序emm
    然后考虑第一问怎么做,由于(n)(a_i)都不大,考虑(O(n^2))的递推。
    如果(i)可以被模出来,那么再用它来对所有(a_i)取次一模,找到新的能被模出来的数。
    最后找到最大的比a_1小的能模出来的数,就是第一问的答案了。记为ans1。
    然后是第二问,和第一问思路类似。
    用第一问答案反推。令(f_i)表示在(i)的时候,只考虑比(i)小的模数,最后得到ans1的方案数。
    那么我们在算(f_i)的时候,只需要枚举第一个用来模的数,然后乘个组合数什么的就行了。
    总效率是(O(n^2))的。

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const LL P=998244353;
    const int N=1e6+10;
    int n,X;
    int a[5005];
    bool vis[5005];
    LL f[5005];
    int cnt[5005];
    LL jc[5005];
    LL ny[5005];
    LL C(int x,int y){
        if(y>x) return 0;
        return jc[x]*ny[y]%P*ny[x-y]%P;
    }
    LL add(LL &x,LL y){
        x+=y;if(x>=P)x-=P;
    }
    int main(){
        jc[0]=jc[1]=ny[0]=ny[1]=1;
        for(LL i=2;i<=5000;++i){
            jc[i]=jc[i-1]*i%P;
            ny[i]=(P-P/i)*ny[P%i]%P;
        }
        for(LL i=2;i<=5000;++i){
            ny[i]=ny[i-1]*ny[i]%P;
        }
        scanf("%d%d",&n,&X);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+1+n);
        vis[X]=1;
        for(int i=X;i>=1;--i){
            if(vis[i])
            for(int j=1;j<=n;++j){
                if(i>=a[j]) vis[i%a[j]]=1;
            }
        }
        int ans1=0;
        for(int i=1;i<a[1];++i) if(vis[i]) ans1=i;
        printf("%d
    ",ans1);
        for(int i=1,j=0;i<=X;++i){
            while(j<n&&a[j+1]<=i) ++j;
            cnt[i]=j;
        }
        f[ans1]=1;
        int Y;
        for(int i=ans1+1;i<=X;++i){
            for(int j=n;j>=1;--j){
                if(a[j]>i) continue;
                Y=i%a[j];
                add(f[i],f[Y]*C(cnt[i]-1,cnt[Y])%P*jc[cnt[i]-1-cnt[Y]]%P);
            }
        }
        LL ans=f[X];
        ans=ans*C(n,cnt[X])%P*jc[n-cnt[X]]%P;
        cout<<ans<<endl;
        return 0;
    }
    

    这个仙人掌太难了,还没写QAQ

  • 相关阅读:
    [LeetCode]N-Queens
    [LeetCode]Anagrams
    [LeetCode]Permutations II
    [LeetCode]Permutations
    [STL]heap和priority_queue
    [STL]deque和stack、queue
    10、小易记单词--2017网易春招
    29、剑指offer--最小的K个数
    28、剑指offer--数组中出现次数超过一半的数字
    9、涂棋盘--2017网易春招
  • 原文地址:https://www.cnblogs.com/Yuigahama/p/13965860.html
Copyright © 2020-2023  润新知