uva11754 Code Feat

229 篇文章 0 订阅
137 篇文章 0 订阅

Hooray! Agent Bauer has shot the terrorists, blown up the bad guy
base, saved the hostages, exposed the moles in the government,
prevented an environmental catastrophe, and found homes for three
orphaned kittens, all in the span of 19 consecutive hours. But now, he
only has 5 hours remaining to deal with his nal challenge: an
activated nuclear bomb protected by a security code. Can you help him
gure out the code and deactivate it? Events occur in real time. The
government hackers at CTU (Counter-Terrorist Unit) have learned some
things about the code, but they still haven’t quite solved it. They
know it’s a single, strictly positive, integer. They also know several
clues of the form \when divided by X , the remainder is one of f Y 1
;Y 2 ;Y 3 ;:::;Y k g “. There are multiple solutions to these clues,
but the code is likely to be one of the smallest ones. So they’d like
you to print out the rst few solutions, in increasing order. The
world is counting on you! Input Input consists of several test cases.
Each test case starts with a line containing C , the number of clues
(1 C 9), and S , the number of desired solutions (1 S 10).
The next C lines each start with two integers X (2 X ) and k (1 k
100), followed by the k distinct integers Y 1 , Y 2 , … , Y k (0
Y 1 ;Y 2 ;:::;Y k < X ). You may assume that the X ‘s in each test
case are pairwise relatively prime (ie, they have no common factor
except 1). Also, the product of the X ‘s will t into a 32-bit
integer. The last test case is followed by a line containing two
zeros. Output For each test case, output S lines containing the S
smallest positive solutions to the clues, in increasing order. Print a
blank line after the output for each test case.

有两种解法,第一种是直接枚举每个集合中取哪个元素,然后用中国剩余定理,复杂度O(πklogπk)。
另一种是找到一个k/x最小的条件【让枚举的解尽可能稀疏】,直接枚举解去验证,复杂度不好估计,但是在πk比较大的时候,解的分布比较密集,速度不会太慢。
当πk比较小的时候选择第一种,否则选择第二种,就可以过了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define LL long long
const int c=10000;
LL yy[12][110],xx[12],ans[100010],M,a[12];
int kk[12],n,s,tot;
void init()
{
    int i,j;
    for (i=1;i<=n;i++)
    {
        scanf("%lld%d",&xx[i],&kk[i]);
        for (j=1;j<=kk[i];j++)
          scanf("%lld",&yy[i][j]);
        sort(yy[i]+1,yy[i]+kk[i]+1);
    }
}
void gcd(LL a,LL b,LL &x,LL &y)
{
    if (!b)
    {
        x=1;
        y=0;
        return;
    }
    gcd(b,a%b,y,x);
    y-=a/b*x;
}
void dfs(int now)
{
    int i;
    LL p,q,x=0;
    if (now==n+1)
    {
        for (i=1;i<=n;i++)
        {
            gcd(M/xx[i],xx[i],p,q);
            p=(p%M+M)%M;
            x=(x+M/xx[i]*p%M*a[i]%M)%M;
        }
        ans[++tot]=x;
    }
    else
      for (i=1;i<=kk[now];i++)
      {
          a[now]=yy[now][i];
          dfs(now+1);
      }
}
void solve1()
{
    int i,j;
    M=1;
    for (i=1;i<=n;i++)
      M*=xx[i];
    tot=0;
    dfs(1);
    sort(ans+1,ans+tot+1);
    for (i=0;s;i++)
      for (j=1;j<=tot&&s;j++)
      if (M*i+ans[j])
      {
        printf("%lld\n",M*i+ans[j]);
        s--;
      }
}
void solve2()
{
    int i,j,k,p=1,l,r,mid;
    bool flag;
    LL x,tem;
    double now=(double)kk[1]/xx[1];
    for (i=2;i<=n;i++)
      if ((double)kk[i]/xx[i]<now)
      {
        p=i;
        now=kk[i]/xx[i];
      }
    for (i=0;s;i++)
      for (j=1;j<=kk[p]&&s;j++)
      {
        x=i*xx[p]+yy[p][j];
        if (!x) continue;
        flag=1;
        for (k=1;k<=n&&flag;k++)
        {
            tem=x%xx[k];
            l=1;
            r=kk[k];
            while (l<r)
            {
                mid=(l+r)/2;
                if (yy[k][mid]>=tem) r=mid;
                else l=mid+1;
            }
            flag=(yy[k][l]==tem);
        }
        if (flag)
        {
            printf("%lld\n",x);
            s--;
        }
      }
}
int main()
{
    int i;
    LL t;
    while (scanf("%d%d",&n,&s)&&n)
    {
        init();
        t=1;
        for (i=1;i<=n;i++)
          t*=kk[i];
        if (t<=c) solve1();
        else solve2();
        putchar('\n');
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值