Codeforces 354C Vasya and Beautiful Arrays[dp+暴力]

题意:

给出n个整数,对每个整数可以减去0-k的任意一个数

求这样操作后,n个数的最大GCD是多少

分析:

我们首先可以知道n个整数中最小的数是多少

而且,最终的答案肯定不大于这个数

这个n个整数中最小的数是答案的上限

然后对于答案的下限

可以肯定的是

1肯定是答案的下限

2呢?3呢?为什么1一定是

其实,0-k+1,都可以作为答案

为什么?

可以把k想象成一个剪刀

对k+1来说,任何数都可以剪掉0-k变成k+1的倍数(任何数模k+1的结果都是0-k)

所以0-k也可以,综上0-k+1都可以,所以答案的下限是k+1

答案处于[k+1,minn]

如果minn<k+1,那么就是minn

如果minn>k+1,则我们枚举这其中所有的数

看最大的能使得所有数列中的数经过操作之后GCD(all)确实能等于这个数的数是多少

也就是验证这个数的可行性,找出可行的数中最大的那个

怎么验证呢?给出一个数m,怎么才能知道可行不可行呢?

一步步来推理

每个数模m,结果都是0--m-1

对于0--m-1,我们的剪刀最多只能剪掉k

所以如果数列中某个数模m的结果大于k,则m不可行

那么我们是不是能这样做

对数列中的每一个数都模m呢

估计一下复杂度,枚举是100W,最多有30万个数,则100w*30w,T!

转化一下这个问题

我们是对每个数尝试一下它是不是处于可行区间

反过来,如果可行区间有这个数的话,是一样的

如果所有可行区间中存在的数的和是n,则这个m是可行的

可行区间是什么?

一个数模m即是x =m*d+x%m

x%m小于等于k,也就是x处于[m*d,m*d+k]

那么所有的可行区间就是

[m*1,m*1+k],[m*2,m*2+k],[m*3,m*3+k],[m*4,m*4+k]...

有logn个这样的区间

算下复杂度,n*logn

这些区间内出现的数的总和我们可以累加前缀和之差得到

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
const int NN=555555;
int vistmp[NN*2];
int vis[NN*2];
int f[NN];
int n,k;
int maxn;
bool check(int s){
	int sum=0;
	for(int i=1;i*s<=maxn;i++){
		sum += vis[min(maxn,i*s+k)] - vis[i*s-1];//注意细节
		if(s==7){
		}
	}
	return sum==n;
}
int main(){
    #ifndef ONLINE_JUDGE
        freopen("G:/in.txt","r",stdin);
        //freopen("G:/myout.txt","w",stdout);
    #endif
	cin>>n>>k;
	int minn=1<<30;
	for(int i=1;i<=n;i++){
		cin>>f[i];
		minn=min(minn,f[i]);
		maxn=max(maxn,f[i]);
		vistmp[f[i]]++;
	}
	vis[minn]=vistmp[minn];
	for(int i=minn+1;i<=maxn;i++)
        vis[i]=vis[i-1]+vistmp[i];
	if(minn<=k+1){
		cout<<minn<<endl;
		return 0;
	}
	for(int i=minn;i>=k+1;i--){
		if(check(i)){
			cout<<i<<endl;
			return 0;
		}
	}
}
时间: 2024-11-09 06:26:38

Codeforces 354C Vasya and Beautiful Arrays[dp+暴力]的相关文章

Codeforces 132C. Vasya and Beautiful Arrays【DP,dfs】

题目大意: 在一根数轴上有一只机器龟,它能够听从人们给它的指令做出向前走一步(F)和向后转(T)的操作.给出初始操作,你最开始有修改n步指令的权利(每一个指令可以被修改很多次),问在你修改n次之后,海龟离原点的最大距离. 做法: 很直观的想法,尽可能的将T转化为F,也算是一种贪心的做法吧. 我们用dfs(i,j,t,cur),其中i表示当前遍历的命令的序号,j表示从0~i过程中我转换了多少个T,t表示从0~i的序号中总共出现了多少次T,cur表示当前相对于原点的距离(有正有负),dp[i][dr

Codeforces 1032F Vasya and Maximum Matching dp

Vasya and Maximum Matching 首先能观察出, 只有完美匹配的情况下方案数唯一. dp[ i ][ 0 ], dp[ i ][ 1 ], dp[ i ][ 2 ] 分别表示 对于 i 这棵子树   0: 不向上连边完成  1:向上连边完成  2:向上连边未完成   的方案数 #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #

CF354C Vasya and Beautiful Arrays

这题感觉可海星a....网上题解包括官方题解的时间复杂度都玄学得一匹,数据比较弱吧....不卡..... 发现一位大佬做法值得学习. 首先要找序列所有数的最大公因数,肯定上界是最小的那个数吧.然后我们排序遍历每一个数,若发现不满足的数,即a[i]%ans>k(不能在k的范围内调整): 那么ans=a[i]/(a[i]/ans+1);这样能最小范围地调整并且省去一些多余的判断,比如ans=8,a[i]=11;ans=11/2=5,可以直接省去中间判断6,7的过程. 此时跳出再判断,当一遍下来不需要

Codeforces 57C Array dp暴力找规律

题目链接:点击打开链接 先是计算非递增的方案, 若非递增的方案数为x, 则非递减的方案数也是x 答案就是 2*x - n 只需求得x即可. 可以先写个n3的dp,然后发现规律是 C(n-1, 2*n-1) 然后套个逆元即可. #include<iostream> #include<cstdio> #include<vector> #include<string.h> using namespace std; #define ll long long #def

Codeforces 837E Vasya&#39;s Function - 数论

Vasya is studying number theory. He has denoted a function f(a, b) such that: f(a, 0) = 0; f(a, b) = 1 + f(a, b - gcd(a, b)), where gcd(a, b) is the greatest common divisor of a and b. Vasya has two numbers x and y, and he wants to calculate f(x, y).

Ural 1353 Milliard Vasya&#39;s Function(DP)

题目地址:Ural 1353 定义dp[i][j],表示当前位数为i位时,各位数和为j的个数. 对于第i位数来说,总可以看成在前i-1位后面加上一个0~9,所以状态转移方程就很容易出来了: dp[i][j]=dp[i][j]+dp[i][j-1]+dp[i][j-2]+.......+dp[i][j-9]: 最后统计即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <

区间Dp 暴力枚举+动态规划 Hdu1081

F - 最大子矩形 Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u Submit Status Description Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located withi

Codeforces 6D Lizards and Basements 2 dfs+暴力

题目链接:点击打开链接 #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<math.h> #include<queue> #include<string> #include<stdlib.h> #include<a

CodeForces 540D Bad Luck Island 概率dp

CodeForces 540D 应该是简单概率dp,由于写得少显得十分蠢萌 求期望逆推,求概率正推,大概是这么个意思,贴一发留恋 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define db double const int maxn=108; db dp[maxn][maxn][maxn]; int main() { int i,j,n,m,k,p; whi