思维——CF1796C Maximum Set(EDU144 div2)

传送门: Problem - C - Codeforces

题意:经分析可以知道题目第一问就是拿L不断乘2,直到L大于R,此时就是最长的长度len

,第二问要求都有多少条同样长的子序列,这个子序列我们分为两种情况

情况1:

一个是开头的第一个元素L1不同但是后面的数都是前一个乘2,这样就可以通过O(1)的时间复杂度知道,通过ans1=R/(pow(2,len-1))-L+1得到,如在[4,100]中有如下三种:

原本是L*pow(2,len-1)<=R,现在R/(pow(2,len-1))变成最大的可行L1,在下面就是6, 6-4+1=3

4 8 16 32 64 
5 10 20 40 80
6 12 24 48 96

情况2:

开头元素还是和情况1里面的开头元素一样,但是中间乘的元素以及顺序不同,比如还是在[4,100]中有如下的情况,依旧是乘4个数,不过其中一个数字已经不一样了,而且乘的顺序也不同

4 8 16 32 96   (2  2  2  3)
4 8 16 48 96   (2  2  3  2)
4 8 24 48 96   (2  3  2  2)
4 12 24 48 96  (3  2  2  2)

在这里有两个重要的点要清楚,

一个是这里乘的数最多只能是2或3,如果出现出现4以及以上的数字说明有更长的序列,比如4可以分成两个2,这样最长序列就变长了一位。

第二个就是这里乘的数最多也只能出现一个3,还是和上面一样,如果出现两个3那么明明就可以去乘3个2,这样就会有更优的序列长度

搞懂了这两个点之后我们只需要看在上面的只能乘2的及基本序列里面有哪一个L1是在*3/2只能依旧小于R的,在这里也是可以通过一个公式在O(1)的时间复杂度得到,和上面求乘数全是2的原理相同,现在先设p=pow(2,len-1)*3/2; 上面是求在[L,R]里面有多少个数乘pow(2,len-1)之后依旧小于等于R,现在是求在[L,R]中有多少个数字L1满足L1*p<=R

,依旧是ans2=R/p-L+1

现在我们知道了有多少条基本序列(情况1里面的)满足可以将乘数里面的一个2替换成3 ,

但是3的位置有len-1个可以选

所以满足要求的序列个数为(ans1+ans2*(len-1))

特判:当长度为1时需要特判

正确代码:

// Problem: C. Maximum Set
// Contest: Codeforces - Educational Codeforces Round 144 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1796/problem/C
// Memory Limit: 512 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> PII;
const int N = 2e5 + 10, mod = 998244353;
int d[N];
int a[N];
int n, t, s, m;
signed main() {
  int t;
  scanf("%lld", &t);
  while (t--) {
    int l, r;
    scanf("%lld%lld", &l, &r);
    int len = 0;
    int tmp = l;
    while (tmp <= r) {
      len++;
      tmp *= 2;
    }
    int ans1 = (r / pow(2, len - 1)) - l + 1;
    int p = pow(2, len - 1) * 3 / 2;
    int ans2 = r / p - l + 1;
    if (len == 1) {
      printf("1 %lld\n", r - l + 1);
    } else {
      printf("%lld %lld\n", len,
             (ans1 + max((int)0, ans2) * (len - 1) % mod) % mod);
    }
  }

  return 0;
}

现在先再贴一个超时且思考的不全面的但是做法是正确的代码:

1.考虑到了乘数只能是2或3但是没考虑到3的数量只能是1

2.没想到能通过两条式子。

// Problem: C. Maximum Set
// Contest: Codeforces - Educational Codeforces Round 144 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1796/problem/C
// Memory Limit: 512 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> PII;
const int N = 2e5 + 10, mod = 998244353;
int d[N];
int a[N];
int n, t, s, m;
int cnt[N];
int c[510][510];
void init() {
  for (int i = 0; i < 500; i++)
    for (int j = 0; j <= i; j++)
      if (!j)
        c[i][j] = 1;
      else
        c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}

int get(int l, int r) {
  int ans = 0;
  while (l <= r) {
    ans++;
    l *= 2;
  }
  return ans;
}
signed main() {
  init();
  int t;
  scanf("%lld", &t);
  while (t--) {
    int l, r;
    scanf("%lld%lld", &l, &r);
    int ans = get(l, r);
    printf("%lld ", ans);
    ans--;
    int cnt = 1;
    if (l == 1) {
      printf("1\n");
      continue;
    }
    for (int i = l; i <= r; i++) {
      if (i * (1 << ans) > r) break;
      int t = i * (1 << ans);
      int cnt3 = 0;
      while (t / 2 * 3 <= r) {
        cnt3++;
        t = t / 2 * 3;
      }

      if (cnt3 == 0 && i != l) {
        cnt++;
        continue;
      }
      for (int k = 1; k <= cnt3; k++) cnt = (cnt + c[ans - k + 1][k]) % mod;

      //  cout << cnt3 << endl;
    }
    printf("%lld\n", cnt);
  }

  return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值