qduoj 153 cfenglv的一道简单签到题 (二分+分解因子)

37 篇文章 0 订阅
24 篇文章 0 订阅


cfenglv的一道简单签到题

发布时间: 2017年6月11日 17:59   最后更新: 2017年6月11日 18:11   时间限制: 4000ms   内存限制: 128M

据说,julyc决定给学弟学妹出一场月赛,于是他脑中浮现了许多很棒棒的出题创意。

而cfenglv恰巧在机房,于是他把一道题的创意说给了cfenglv听:

求区间gcd(最大公约数)大于等于k的最大区间长度len

这个问题cfenglv思考了一下,发现可以做,但是又不想做,于是提议放到月赛上给其他人做,julyc表示同意。

那么,你能把这个这么棒棒的问题给解决吗?

第一行一个整数t代表数据组数
接下来每组数据
第一行输入两个整数n,k
0<n,k<=1e5
接下来n个正整数
保证所有数据不大于1e5

每组数据输出一行,并输出ans

  复制
1
5 3
3 6 9 2 5 
3
思路: 二分长度, 把每个数所有因子都提出来,如果某一段区间有超过这段区间长度个因子,并且这个因子》=k就好了, 因子最多sqrt*2, 那么总的复杂度就是 sqrt*2*n*log 1e7左右。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 1e5 + 5;
vector<int> fac[maxn];
int a[maxn], cnt[maxn], t, n, k;
int check(int x)  //这里比较巧妙, 先从头找长度x个,然后不断向左移动, 移动时候 就先把第一个的因子删掉,加上新的这个因子就好了。。两个for
{
    for(int i = 1; i <= x; i++)
    {
        for(int j = 0; j < fac[i].size(); j++)
        {
            cnt[fac[i][j]]++;
            if(cnt[fac[i][j]] >= x && fac[i][j] >= k) return 1;
        }
    }
    for(int i = x+1; i <= n; i++)
    {
        int tem = i-x;
        for(int j = 0; j < fac[tem].size(); j++)
            cnt[fac[tem][j]]--;
        for(int j = 0; j < fac[i].size(); j++)
        {
            cnt[fac[i][j]]++;
            if(cnt[fac[i][j]] >= x && fac[i][j] >= k) return 1;
        }
    }
    return 0;
}
int main()
{
    cin >> t;
    while(t--)
    {
        for(int i = 1; i <= n; i++)
            fac[i].clear();
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= sqrt(a[i]); j++)
            {
                if(a[i]%j) continue;
                fac[i].push_back(j);
                if(a[i]/j != j)
                    fac[i].push_back(a[i]/j);
            }
        }
        int l = 1, r = n, mid, ans = 0;
        while(l <= r)
        {
            mid = (l+r)/2;
            if(check(mid)) ans = mid, l = mid + 1;
            r = mid - 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}


一共 就1e5 ,可以把1-1e5所有的的数的因子都找出来, 那样就不用每次都打表了 标程代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
vector<int>g[maxn];
int num[maxn],a[maxn];
void get_div(int n) 
{
	for(int i=1;i*i<=n;i++)
	{
		if(n%i==0)
		{
			if(n/i!=i)
			g[n].push_back(n/i);
			g[n].push_back(i);
		}
	}
}
void init()  //把所有的数的因子都弄出来
{
	for(int i=1;i<=1e5;i++)
		get_div(i);
}
int check(int len,int k,int n)
{
	memset(num,0,sizeof(num));
	for(int i=1;i<=len;i++)
	{
		for(int j=0;j<g[a[i]].size();j++)
		{
			if(g[a[i]][j]<k)
			continue;
			num[g[a[i]][j]]++;
			if(num[g[a[i]][j]]==len)
			return 1;
		}
	}
	for(int i=len+1;i<=n;i++)
	{
		for(int j=0;j<g[a[i-len]].size();j++)
		{
			if(g[a[i-len]][j]<k)
			continue;
			num[g[a[i-len]][j]]--;
		}
		for(int j=0;j<g[a[i]].size();j++)
		{
			if(g[a[i]][j]<k)
			continue;
			num[g[a[i]][j]]++;
			if(num[g[a[i]][j]]==len)
			return 1;
		}
	}
	return 0;
}
int main()
{
	int t;
	init();
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	scanf("%d",&t);
	while(t--)
	{
		int n,k;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
		int l=0,r=n+1;
		while(r-l>1)
		{
			int mid=(l+r)/2;
			if(check(mid,k,n))
			l=mid;
			else
			r=mid;
		}
	//	printf("test %d\n",a[100000-50]);
		printf("%d\n",l);
	}
	return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值