CF1631F. Flipping Range dp **

link
dp, 2400,非常妙的一道题目
类似这种每次操作都是对连续 k k k 位进行的不妨用对位置取模的dp

题意

给定数组 a a a 和集合 B B B,你可以进行如下操作任意多次(可以为0次): ∀ x ∈ B , 翻 转 数 组 a 中 连 续 的 x 位 , 同 一 个 x 也 可 以 多 次 取 出 \forall x\in B,翻转数组a中连续的x位,同一个x也可以多次取出 xBaxx
问: m a x   Σ a i max\space \Sigma a_i max Σai

思路

首先假设 x , y ∈ B ( x > y ) x,y\in B(x > y) x,yB(x>y),则我们可以把任意一个长度为x-y的区间翻转,容易得到翻转的最小长度即为g=gcd(b1,b2,...bn),所以问题简化为了:

给定 a , g a,g a,g,每次操作可以翻转数组 a a a 中连续的 g g g 位,求 m a x   Σ a max\space\Sigma a max Σa
构造一个数列 c c c ,若最后 a i a_i ai 乘了-1,则 c i = 1 c_i=1 ci=1,否则 c i = 0 。 c_i=0。 ci=0
f x = ⨁ i % g c i , x ∈ [ 0 , g − 1 ] f_x=\bigoplus_{i\%g}c_i,x\in [0,g-1] fx=i%gci,x[0,g1],由于是翻转连续的g位,所以每次操作相当于 ∀ x ∈ [ 0 , g − 1 ] , f x = f x ⨁ 1 \forall x\in[0,g-1],f_x = f_x\bigoplus1 x[0,g1]fx=fx1也就是无论怎样变换,所有的 f x f_x fx 都是相等的,同为1or同为0。
另一方面,我们也可以通过变换得到任意一个 f x f_x fx 相等的局面,所以f_x均为1或0是一个序列合法的等价条件
以此进行dp。
dp[i][1/0]表示当前进行到第 i i i 位,且进行了1/0(奇/偶次)变换后得到的 a i + a i − g + . . . a_i+a_{i-g}+... ai+aig+...最大值。最后的答案就是1/0中大的那个。

int n, m;
int gcd(int a, int b) {
	if(!b) return a;
	return gcd(b, a % b);
}
int a[maxn];
ll dp[maxn][2];//dp[i][0]表示(i+1)%g位置共操作偶数次 [i][1]表示共操作奇数次
void solve() {
    cin >> n >> m;
    for(int i = 1; i <= n; i++) {
    	cin >> a[i];
    }
    int g = 0;
    while(m--) {
    	int x;
    	cin >> x;
    	g = gcd(g, x);
    }
    // cout << g << endl;
    for(int i = 1; i <= g; i++) {
    	dp[i][1] = -a[i];
    	dp[i][0] = a[i];
    }
    for(int i = g + 1; i <= n; i++) {
    	dp[i][1] = max(dp[i-g][0] - a[i], dp[i-g][1] + a[i]);
    	dp[i][0] = max(dp[i-g][1] - a[i], dp[i-g][0] + a[i]);
    }
    ll sum1 = 0, sum0 = 0;
    for(int i = n-g+1; i <= n; i++) {
    	sum1 += dp[i][1];
    	sum0 += dp[i][0];
    }
    cout << max(sum1, sum0) << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值