把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF1630D Flipping Range

题面传送门
感觉是个二合一。
首先,如果我们有一个数字\(x\)长度,又有一个\(kx\)长度,那么\(kx\)长度是没有用的。
同时,如果有两个长度\(x,y(x,y\leq \frac{n}{2})\),那么显然我们可以组合出最小的\(\gcd (x,y)\)长度。
所以给出的\(m\)个数就是求\(\gcd\)就转变成一个数了。题目变成可以取一段\(x\)乘以\(-1\)
我们按照每个位置\(\bmod x\)分组。因为题目要求最大,所以要让负数最少。
容易发现有以下两种操作:
消去同一组中的两个\(-1\)
同时消去所有组中的一个\(-1\),特别的,如果有的组没有\(-1\),那么会增添一个\(-1\)
所以每一组最多只有一个\(-1\),显然是这一组中最小的。
当我们将当前的\(-1\)消完后,有的组没有-1,有的组有,此时答案可能存在在所有组同时消去-1。特别计算一下。
时间复杂度\(O(n+m+loga)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 1000000
#define M 500000
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (m*x+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound 
using namespace std;
int T,n,m,k,x,W[N+5],A[N+5],ToT,F[N+5];ll Ans,Ns;
I void Solve(){
	RI i;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) scanf("%d",&A[i]);
	ToT=0;while(m--) scanf("%d",&x),ToT=(!ToT?x:__gcd(ToT,x));
	for(i=0;i<ToT;i++)F[i]=1e9,W[i]=0;for(i=1;i<=n;i++) F[i%ToT]=min(F[i%ToT],abs(A[i])),W[i%ToT]+=(A[i]<0);Ans=-1e18;
	Ns=0;for(i=1;i<=n;i++) Ns+=abs(A[i]);for(i=0;i<ToT;i++) W[i]--,W[i]&1&&(Ns-=2*F[i]),W[i]++;Ans=max(Ans,Ns);
	Ns=0;for(i=1;i<=n;i++) Ns+=abs(A[i]);for(i=0;i<ToT;i++) W[i]&1&&(Ns-=2*F[i]);Ans=max(Ans,Ns);printf("%lld\n",Ans);
}
int main(){
//	freopen("1.in","r",stdin);
	scanf("%d",&T);while(T--) Solve();
}
posted @ 2022-02-01 14:51  275307894a  阅读(61)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end