抽签问题

一.题意

你的朋友提议玩一个游戏:将写有数字的n个纸片放入口袋中,你可以从口袋中抽取4次纸片,每次记下纸片上的数字后都将其放回口袋中。如果这4个数字的和是m,就是你赢,否则就是你的朋友赢。你挑战了好几回,结果一次也没赢过,于是怒而撕破口袋,取出所有纸片,检查自己是否真的有赢的可能性。请你编写一个程序,判断当纸片上所写的数字是k1, k2, …, kn时,是否存在抽取4次和为m的方案。如果存在,输出Yes;否则,输出No。(1<=n<=1000,1<=m<=1e8,1<=k<=1e8)

二.解法

2.1 暴力解法

  // 通过四重循环枚举所有方案
  for (int a = 0; a < n; a++) {
    for (int b = 0; b < n; b++) {
      for (int c = 0; c < n; c++) {
        for (int d = 0; d < n; d++) {
          if (k[a] + k[b] + k[c] + k[d] == m) {
            f = true;
          }
        }
      }
    }
  }

2.2 解法

最内层循环即检查是否存在d,使得k[a]+k[b]+k[c]+k[d]==m,将d移到左边

K[d]==m-k[a]-k[b]-k[c],可以对k数组进行排序,查找速度为logn

bool BinarySearch(int x)
{
    int L=0,R=N;
    //x的存在范围是k[L],k[L+1],...k[R-1]
    while(R-L>=1){
        int mid=(L+R)/2;
        if(K[mid]==x) return true; 
        else if (K[mid]<x) L=mid+1;
        else R=mid;
    }

    return false;
}
void solve(){
    sort(K,K+N);
    bool f=false;
    for(int a=0;a<N;++a)
        for(int b=0;b<N;++b)
            for(int c=0;c<N;++c)
                if(BinarySearch(m-k[a]-k[b]-k[c]))
                    f=true;
    if(f) puts("YES");
    else puts("NO");
}

2.3 解法


着眼于内侧的两个循环,检查最内层循环即检查是否存在c,d,使得K[c]+K[d]==m-k[a]-k[b],预先枚举出k[c]+k[d]所得的n^2个数,并排好序,就可以使用二分.

循环时间和排序时间都是

void solve(){
    for(int c=0;c<N;++c)
        for(int d=0;d<N:++d)
            KK[c*N+d]=K[c]+K[d];
    sort(KK,KK+N*N);
}



  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值