传送门: 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;
}