SCZ 20170812 T2 MFS

题面照例十分暴力,我再次重写一下吧……

题目描述

\(n\)个数构成的数列\(A\)元素为\(a_i\),你要构造一个数列\(B\),元素为\(b_i\),使得满足\(b_{i}>0,a_{i}-k\leq b_{i}\leq a_{i}\)使得去除\(f\)个元素后\(b_i\)有公约数\(g\)。一个测试点有多组测试数据,当一个测试点的所有测试数据都与标准答案相同时,该测试点得分。

输入格式

第一行一个整数\(T\),表示数据组数。
对于下面的每一组数据:
第一行,三个整数\(n,k,f\),n表示数列元素个数。
第二行,n个整数\(a_{i}\),表示一个数列。

数据范围

\(A=max_{a_{i}}\)

测试点编号\(n,k,f,A\)\(T\)
\(1,2,3,4,5,6\)\(\leq 10\)\(\leq 3\)
\(7,8,9,10\)\(\leq 3\times 10^3,f=0\)\(\leq 3\)
\(11,12\)\(\leq 5\times 10^3\)\(\leq 3\)
\(13,14\)\(\leq 3\times 10^4\)\(\leq 3\)
\(15,16\)\(\leq 5\times 10^4\)\(\leq 3\)
\(17,18\)\(\leq 5\times 10^5\)\(\leq 3\)
\(19,20\)\(\leq 2\times 10^6\)\(\leq 2\)

题解

30分做法

纯暴力啊……其实我也不知道这30分暴力该怎么写……

60分做法

首先得把这个问题转化成一个可以处理的东西。如果对题意进行归纳后就不难发现,这道题中当\(g\)满足要求时,\(a_{i}<g\ 或\ a_{i}\ mod\ g>k\ 的个数\leq f\)。所以在1至\(A\)中枚举\(g\),根据上述要求判断\(g\)是否符合要求。

代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+10,inf=0x7fffffff;
int a[maxn];
int t,n,k,f;
int main()
{
    int i,j,l,r,g,num,flag;
    cin>>t;
    while(t--)
    {
        cin>>n>>k>>f;r=-inf;
        for(i=1;i<=n;i++){scanf("%d",&a[i]);r=max(r,a[i]);}
        //for(g=1;g<=k+1;g++){printf("%d ",g);}
        for(g=1;g<=r;g++)
        {
            num=0;flag=1;
            for(i=1;i<=n;i++){if(a[i]%g>k||a[i]/g==0){num++;if(num>f){flag=0;break;}}}
            if(flag){printf("%d ",g);}
        }
        cout<<endl;
    }
    return 0;
}

100分做法

考虑优化上述查找过程。
注意发现\(A\)的范围较小,可以使用前缀和。这样就可以统计出满足\(a_{i}\in [l,r]\)的个数了。仍然暴力枚举\(g\),每次统计出满足\(a_{i}\in [k\cdot g+k+1,(k+1)\cdot g]\)的个数并相加,判断其是否大于f即可。

代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e6+10,inf=0x7fffffff;
int a[maxn],s[maxn];
int t,n,k,f;
template<typename T>void read(T &x)
{
    x=0;int f=1;char ch;ch=getchar();
    while(!isdigit(ch)){if(ch=='-'){f=-1;}ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    if(f==-1){x=-x;}
}
int main()
{
    int i,j,r,tmp,num,hd,rr,g;
    cin>>t;
    while(t--)
    {
        cin>>n>>k>>f;r=-inf;
        memset(a,0,sizeof(a));
        for(i=1;i<=n;i++){read(tmp);a[tmp]++;r=max(r,tmp);}
        for(i=1;i<=r;i++){s[i]=s[i-1]+a[i];}
        for(g=1;g<=r;g++)
        {
            num=s[g-1];
            for(i=g;num<=f&&i+k+1<=r;i+=g)
            {
                hd=i+k+1;rr=min(r,i+g-1);
                if(hd<=rr){num+=(s[rr]-s[hd-1]);}
            }
            if(num<=f){printf("%d ",g);}
        }cout<<endl;
    }
    return 0;
}

转载于:https://www.cnblogs.com/XSC637/p/7754967.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值