Educational Codeforces Round 144 (Rated for Div. 2)(C~D)

345 阅读3分钟

C. Maximum Set

题意

给定一个区间[l,r],在这个区间里选择数字组成一个集合,让这个集合的数字都能整除
输出这个集合的数字个数的最大值和能有多少这样大的集合

思路

显然为其中一个所要的集合
也可能是要的集合,当然3的位置可以变换
到这就很明白了,遍历每个数 :::info

  • :::
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6+10,M=998244353;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int l,r,tem=1,tem2,si=1;
        long long sum=0;
        cin>>l>>r;
        while(l*tem*2<=r)tem*=2,si++;
        tem2=tem/2*3;
        //cout<<tem;
        for(int i=l;i<=r;i++)
        {
            if(i*tem>r)break;
            if(i*tem<=r)sum=(sum+1)%M;
            if(i*tem2<=r)sum=(sum+si-1)%M;
        }
        cout<<si<<" "<<sum<<'\n';
    }
    return 0;
}

一交直接超时,因为测试案例实在太多了,就要优化

优化

直接用r去除以就得到了最多能得到几,对于3也是一样的

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6+10,M=998244353;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int l,r,tem=1,tem2,si=1;
        long long sum=0;
        cin>>l>>r;
        while(l*tem*2<=r)tem*=2,si++;
        if(tem==1){cout<<"1 "<<r-l+1<<endl;continue;}
            //cout<<r/tem-l;
        tem2=tem/2*3;
        sum=(r/tem-l+1)%M;
        if(l*tem2<=r)sum+=(r/tem2-l+1)*(si-1)%M;
        cout<<si<<" "<<sum<<'\n';
    }
    return 0;
}

D. Maximum Subarray

题意

给你一个由 n 个整数组成的数组 a1,a2,…,an 。也给了两个整数 k 和 x 。您必须执行操作:将 x 添加到恰好 k 个不同位置的元素上,并从所有其他位置减去 x。例如,如果 a=[2,−1,2,3],k=1,x=2, 并且我们选择了第一个元素,那么在操作之后,数组 a=[4,−3,0,1] 。求操作后数组的最大连续子段和。另外空数组字段和为0;

思路

看这个数据范围只能dp了吧,要注意到k最大不超过20
可以先将所有的 ai 都先减去x这样就简化为在k个不同的位置的元素上加上2*x
状态表示 f[i][j] 在前i个数中在 j个位置加上2*x 并以a[i]结尾的连续子段的和

无效状态

:::info

  • 前i个数不够
  • 因为一定要改变k个数,所以后面的数不够改变 :::

状态转移

无效状态没有表示出来 :::info

  • if j==0 f[i][0]=max(f[i-1][0],0)+a[i]

  • ** if j!=0 f[i][j]=max(f[i-1][j-1]+a[i],a[i])+2*x

               if(i!=j)f[i][j]=max(f[i][j],max(f[i-1][j]+a[i],a[i]));**<br />**                      
    

:::

j==0很容易解释
如果j!=0 就要枚举在i位置要不要加 2*x,当然如果i==j就一定要加

答案的获得

这里的每一个有效的f[i][j]都有可能都是答案

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
const long long inf = -1e18; 
long long a[N];
long long f[N][21];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,k,x;
        f[0][0]=0;
        long long sum=0;
        cin>>n>>k>>x;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            a[i]-=x;
        }
        for(int i=1;i<=k;i++)f[0][i]=inf;
        for(int i=1;i<=n;i++)
        {
            if(i+k<=n)f[i][0]=max(f[i-1][0],0ll)+a[i];
            else f[i][0]=inf;
            for(int j=1;j<=k;j++)
            {
                 if(i>=j&&n-i>=k-j)
                {
                    f[i][j]=max(f[i-1][j-1]+a[i],a[i])+2*x;
                    if(i!=j)f[i][j]=max(f[i][j],max(f[i-1][j]+a[i],a[i]));
                }
                else f[i][j]=inf;
            }
        }
        for(int i=1;i<=n;i++)for(int j=0;j<=k;j++)sum=max(sum,f[i][j]);
        cout<<sum<<endl;
    }
}