zoukankan      html  css  js  c++  java
  • UVA 11754 (暴力+中国剩余定理)

    题目链接http://www.bnuoj.com/v3/problem_show.php?pid=20172

    题目大意:有C个模方程,每个方程可能有k余数,求最小的S个解。

    解题思路

    看见模方程就想到中国剩余定理,然后看下确定的方程情况。

    由乘法原理,共有II ki 种情况,即求解II ki 次。k比较大时基本完蛋。

    其实解模方程还有一种暴力方法,就是选定一个模方程,令t=0,1...., n=t*LCM+余数(n一定要大于0)

    通过t不断增大这种迭代方式从小到大创造一些可能解n,然后去测试其它方程,看余数对不对。

    如果余数全对,那么就找到了一个解。否则就砍掉。

    因为测试是很快的,大部分数据一开始就被砍了,所以k比较大时速度非常快。

     

    毕竟上面是看RP的暴力,所以设定一个分界(10000),如果II ki <10000 ,那么还是通过中国剩余定理来求解,复杂度O(n)。

    方法就是DFS枚举出C个余数情况,然后求解。

    由于求出的全是最小整数解,S比较大时,剩余定理的解可能不足,这时候从小到大每个值加M的倍数凑出更大的解。

     

    #include "cstdio"
    #include "set"
    #include "vector"
    #include "algorithm"
    using namespace std;
    #define LL long long
    #define LIMIT 10000
    int C,S,s;
    LL m[15],k[15],y[15][105],a[15],M;
    set<LL> value[15];
    vector<LL> ans;
    void solve_violence(int bc)
    {
        for(int i=1;i<=C;i++)
        {
            value[i].clear();
            if(i!=bc) for(int j=1;j<=k[i];j++) value[i].insert(y[i][j]);
        }
       for(int t=0;S!=0;t++)
        {
            for(int i=1;i<=k[bc];i++)
            {
                LL n=t*m[bc]+y[bc][i];
                if(!n) continue;
                bool ok=true;
                for(int j=1;j<=C;j++)
                {
                    if(j==bc) continue;
                    if(!value[j].count(n%m[j])) {ok=false;break;}
                }
                if(ok) {printf("%lld
    ",n);if(--S==0) return;}
            }
        }
    }
    LL ex_gcd(LL a,LL b,LL &x,LL &y)
    {
        if(a==0&&b==0) return -1;
        if(b==0) {x=1;y=0;return a;}
        LL d=ex_gcd(b,a%b,y,x);
        y-=a/b*x;
        return d;
    }
    LL solve_china()
    {
        LL res=0;M=1;
        for(int i=1;i<=C;i++) M*=m[i];
        for(int i=1;i<=C;i++)
        {
            LL w=M/m[i],x,y;
            ex_gcd(m[i],w,x,y);
            y=(y*w%M+M)%M;
            res=(res+y*a[i])%M;
        }
        return res;
    }
    void dfs(int dep)
    {
        if(dep>C)
        {
            ans.push_back(solve_china());
            return;
        }
        for(int i=1;i<=k[dep];i++)
        {
            a[dep]=y[dep][i];
            dfs(dep+1);
        }
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(scanf("%d%d",&C,&S)&&C)
        {
            int bestc=1;ans.clear();s=S;M=1;
            LL tot=1;
            for(int i=1;i<=C;i++)
            {
                scanf("%lld%lld",&m[i],&k[i]);
                tot*=k[i];
                if(k[i]*m[bestc]<k[bestc]*m[i]) bestc=i;
                for(int j=1;j<=k[i];j++)  scanf("%lld",&y[i][j]);
                sort(y[i]+1,y[i]+1+k[i]);
            }
            if(tot<LIMIT)
            {
                dfs(1);
                sort(ans.begin(),ans.end());
                for(int t=0;S!=0;t++)
                    for(int i=0;i<ans.size();i++)
                {
                    LL n=t*M+ans[i];
                    if(n>0)
                    {
                        printf("%lld
    ",n);
                        if(--S==0) break;
                    }
                }
            }
            else solve_violence(bestc);
            printf("
    ");
        }
    }
    neopenx 445520 20172 Accepted GNU C++ 26 ms   2223 B 2015-02-06 23:10:03
  • 相关阅读:
    用OKR让你的员工嗨起来
    用数据让我们的OKR变得“冷酷”却更有价值
    好的想法只是OKR的开始创业者谨记
    “OKR播种机”JOHN DOERR–目标是对抗纷乱思绪的一针疫苗
    用OKR提升员工的执行力
    OKR的两个基本原则
    《OKR工作法》| 一次说太多等于什么都没说
    《OKR工作法》–让所有人承担自己的职责
    《OKR工作法》——打造一支专一的团队
    Oracle wm_concat()函数的实际运用
  • 原文地址:https://www.cnblogs.com/neopenx/p/4278197.html
Copyright © 2011-2022 走看看