Educational Codeforces Round 144 (Rated for Div. 2) (C-D)题解
C. Maximum Set
题目大意:
给你两个整数 l l l 和 r r r。从 l l l 到 r r r 选一些数组成漂亮集合,漂亮集合满足任意一个数 x x x 可以被集合种的另一个数 y y y 整除,或者 y y y 整除 x x x :
-
所有元素都从 l l l 到 r r r 的美丽集合的最大可能大小;
-
由具有最大可能大小的 l l l 到 r r r 的整数组成的漂亮集合的数量。
-
由于第二个数字可能非常大,请将其以 998244353 998244353 998244353 的模打印。
思路:
-
需要从 l l l开始乘,假设 l l l × \times × 2 t 2^t 2t <= r r r, t t t 尽可能大,此时的 t t t 便是最大的大小。
-
另外 l l l × \times × 2 t − 1 2^{t-1} 2t−1 × \times × 3 3 3 <= r r r,也有可能满足。而且 乘 3 3 3 的地方可以在 t t t个位置中选一个。
-
其次 ( l + x ) (l+x) (l+x) × \times × 2 t 2^{t} 2t <= r r r 也需要考虑。
-
为什么只需考虑2,3,可以结合唯一分解定理去思考。
code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define Please return
#define Accepted 0
#define int long long
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<double, double> PDD;
const int N = 1000010,M=2*N,INF=0x3f3f3f3f,mod=998244353 ;
int n;
void slove(int _case)
{
int l,r;
cin>>l>>r;
int t=__lg(r/l),tmp=1<<t;
int ans=0;
ans+=(r/tmp-l+1);
tmp=tmp*3ll/2ll;
if(tmp*l<=r){
ans=(ans+t*(r/tmp-l+1)%mod)%mod;
}
cout<<t+1<<" "<<ans<<endl;
}
signed main()
{
ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T=1;
cin>>T;
for(int _case=1;_case<=T;_case++)
{
slove(_case);
}
Please Accepted;
}
D. Maximum Subarray
题目大意:
给你一个由 n n n 个整数组成的数组 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,…,an。也给了两个整数 k k k 和 x x x 。您必须执行操作:将 x x x 添加到恰好 k k k 个不同位置的元素上,并从所有其他位置减去 x x x。例如,如果 a = [ 2 , − 1 , 2 , 3 ] , k = 1 , x = 2 , a=[2,−1,2,3],k=1,x=2, a=[2,−1,2,3],k=1,x=2,并且我们选择了第一个元素,那么在操作之后,数组 a = [ 4 , − 3 , 0 , 1 ] a=[4,−3,0,1] a=[4,−3,0,1] 。求操作后数组的最大子段和。另外空数组字段和为0;
思路:
-
考虑DP,区间 [ j , i ] [j,i] [j,i] 操作 p p p 个位置。由于此题 0 0 0 ⩽ \leqslant ⩽ k k k ⩽ \leqslant ⩽ m i n ( 20 , n ) min(20,n) min(20,n),所以枚举的 1 1 1 ⩽ \leqslant ⩽ j j j ⩽ \leqslant ⩽ m i n ( k , i ) min(k,i) min(k,i)。剩余细节见代码
code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define Please return
#define Accepted 0
#define int long long
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<double, double> PDD;
const int N = 200010,M=2*N,INF=1e18,mod=998244353 ;
int n,k,x;
int a[N],minn[N];
void slove(int _case)
{
//a[r]-a[l-1]+p*x-(r-l+1-p)*x
//a[r]-a[l-1]+2*p*x-r*x+(l-1)*x
//(a[r]-r*x)-(a[l-1]-(l-1)*x)+2*p*x
//0<=p<=min(k,r-l+1)
//n-(r-l+1)>=k-p
cin>>n>>k>>x;
for(int i=0;i<=n;i++) a[i]=0;
for(int i=0;i<=k;i++) minn[i]=INF;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)a[i]+=a[i-1];
for(int i=1;i<=n;i++)a[i]-=i*x;
int ans=0;
if(!k){
int t=a[0];
for(int i=1;i<=n;i++) ans=max(ans,a[i]-t),t=min(t,a[i]);
}
for(int i=0;i<=n;i++)
{
for(int j=1;j<=min(k,i);j++)
{
for(int p=0;p<=min(k,i-j+1);p++)
{
if(n-i+j-1>=k-p)//[j,i]操作P个
ans=max(ans,a[i]-a[j-1]+2ll*p*x);
}
}
for(int j=1;j<=k;j++)
{
if(i-j>=k){
minn[j]=min(minn[j],a[i-j]);
}
}
for(int j=1;j<=k;j++)
{
if(i-j>=k){//第i位向前操作j个
//这里为什么需要,前面[j,i]操作P个,但可能[j+1,i]操作P个更优,而j+1可能就大于k了。
ans=max(ans,a[i]-minn[j]+max(0ll,2ll*j*x));
}
}
}
cout<<ans<<endl;
}
signed main()
{
ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T=1;
cin>>T;
for(int _case=1;_case<=T;_case++)
{
slove(_case);
}
Please Accepted;
}