首页 > 其他分享 >CF GYM 104020 G

CF GYM 104020 G

时间:2023-11-01 19:13:58浏览次数:34  
标签:104020 int GYM 个数 CF dp

link

首先,因为 \(w_i\le 10^6\),有点大,所以我们想方设法把他变小一点。

设一个快为 \(w_i=k\times x+r\)。其实,如果我们把他分为 \(x\) 个大小为 \(k\) 的块,然后一个大小为 \(r\) 的块是最优的。因为切成其他的大小的块,我们可以调整成这种切法,答案不是更劣。比如说,有 9 3 4 这三个快,\(k=8\)。你可以使 \(9=4+5\),然后 \(3,5\)、\(4,4\) 配对。但是你也可以 \(9=8+1\),然后 \(3,4,1\)、\(8\) 配对。

然后我们就把 \(w_i\) 弄成了 \(<k\) 的大小。(其实就是模 \(k\))。注意这个切也要算入答案。

现在考虑另一件事情。你有若干个 \(<k\) 大小的块,计个数为 \(cnt_1,cnt_2,\cdots cnt_{k-1}\)。对于 \(1\le i < \frac{k}{2}\),我们可以使 \(i\) 与 \(k-i\) 配对,即对于 \(1\le i < \frac{k}{2}\),\(cnt_{i}\) 和 \(cnt_{k-i}\) 均减 \(\min(cnt_i,cnt_{k-i})\),不需要任何切。发现这样切完以后,\(cnt_i>0\) 的 \(i\) 最多有 \(4\) 个(\(k=8\) 的情况),即 \(1\) 或 \(7\),\(2\) 或 \(6\),\(3\) 或 \(5\) 和 \(4\)。设这些非零的数为 \(b_0\sim b_3\)。如果小于四个,\(b_i\) 就是 \(0\)。

考虑,这些块的个数均小于 \(n\),也就是 \(100\)。实际上,个数的组合最多有 \(25^4\) 种。这时候就可以 dp 了。设 \(dp_{i,j,k,l}\) 代表用 \(i\) 个 \(b_0\),\(j\) 个 \(b_1\),\(k\) 个 \(b_2\),\(l\) 个 \(b_3\) 的,的什么呢?

这时候就要进行一个题目的转化。我们不难发现,原来的题目等同于:

给你一些 \(<k\) 大小的方块。设他们的和为 \(a\times k\)。现在,把他们分成若干组,设为 \(b\) 组,使得每一组的大小和都是 \(k\) 的倍数。最大化 \(a-b\)。

这样为什么是对的呢?不切的情况下,显然 \(a=b\)。如果你切了一下,那就一定要和另一个(或多个)方块组合,就会少掉一组,即 \(b=b-1\)。

所以,dp 就是最多能分出的组的个数。转移很显然。

复杂度 \(\mathcal{O}(n^4)\),但其实很松。

Code
#include <bits/stdc++.h>

using namespace std;

#define de(x) cout<<#x<<"="<<x<<endl

using ll = long long;

int n,K,a[111],ans;
int cnt[8],sum,id[4],c[4]; 

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin>>n>>K;
	for (int i=0; i<n; i++){
		cin>>a[i];
		ans+=a[i]/K-(a[i]%K==0);
		cnt[a[i]%K]++;
	}
	for (int i=1; i<K/2; i++){
		int mnu=min(cnt[i],cnt[K-i]);
		cnt[i]-=mnu;
		cnt[K-i]-=mnu;
	}
	int tot=0;
	for (int i=1; i<K; i++){
		if (cnt[i]){
			id[tot++]=i;
			c[tot-1]=cnt[i];
			sum+=i*cnt[i];
		}
	}
	ans+=sum/K;
	int dp[c[0]+1][c[1]+1][c[2]+1][c[3]+1];
	for (int i=0; i<c[0]+1; i++){
		for (int j=0; j<c[1]+1; j++){
			for (int k=0; k<c[2]+1; k++){
				for (int l=0; l<c[3]+1; l++){
					auto &pd=dp[i][j][k][l];
					pd=0;
					if (i){
						pd=max(pd,dp[i-1][j][k][l]);
					}
					if (j){
						pd=max(pd,dp[i][j-1][k][l]);
					}
					if (k){
						pd=max(pd,dp[i][j][k-1][l]);
					}
					if (l){
						pd=max(pd,dp[i][j][k][l-1]);
					}
					if ((i*id[0]+j*id[1]+k*id[2]+l*id[3])%K==0){
						pd++;
					}
				}
			}
		}
	}
	ans-=dp[c[0]][c[1]][c[2]][c[3]]-1;
	cout<<ans<<endl;
	return 0;
}

// don't waste time!!!

标签:104020,int,GYM,个数,CF,dp
From: https://www.cnblogs.com/SFlyer/p/17803845.html

相关文章

  • [CF576E] Painting Edges
    PaintingEdges动态加边和二分图容易想线段树分治,分别维护k种颜色的并查集。不过每条边的存在时间不能确定。设边i的两次操作的时间为\(x_i,y_i\),那么对于\(t\in[x_i+1,y_i-1]\)有两种情况,颜色改变或改色不变。则我们把每次操作影响的时间放在树上,从左到右递归到叶......
  • CF1025F Disjoint Triangles
    虽然我不懂计算几何,但是两个三角形互相进入,感觉很涩啊!——By【】考虑两个互不相交的三角形,寻找一个方式能够不重不漏地统计它们。容易发现两条不交的线段\(A_1A_2,B_1B_2\)之间,必然存在一条直线将\(A_1A_2,B_1B_2\)分在直线两端,且与\(A_1A_2,B_1B_2\)无交。证明的话,......
  • CF908H New Year and Boolean Bridges
    这说明你那破子集卷积不是万能的。显然题目要求的图\(G'\)是弱联通的,考虑给出的图\(G\)中两个点\(i,j\)之间\(G_{i,j}\)的条件转化为:\(G_{i,j}=\mathttA\),说明\(i\)能到\(j\)且\(j\)能到\(i\),则\(i,j\)在\(G'\)的同一个强连通分量中。\(G_{i,j}=\mathttO......
  • WCF restful 上传文件 返回413 request entity too large
    网上各种加binding都不行最后找到了在配置文件中加 webHttpBinding1<system.serviceModel>2<bindings>3<webHttpBinding>4<binding5maxBufferPoolSize="2048576000"6......
  • CF484D Kindergarten
    CF484DKindergarten题目描述:有一组数,你要把他分成若干连续段。每一段的值,定义为这一段数中最大值与最小值的差。求一种分法,使得这若干段的值的和最大。数据范围:\(N<10^6\),\(a[i]<10^9\)。思路:仔细手摸几组数据,你会发现,我们将原序列分好后,每一段肯定是一个递增或者......
  • CF练习题17(DP)
    ChocolateBar我们看到\(n,m\le30\)想到暴搜。考虑枚举分割线,一直到刚好满足需要或者只有一个巧克力的情况。随手跑了个最优解。inlineintdfs(intn,intm,intk){ if(n*m==k)return0; if(k<=0)return0; if(f[n][m][k]<inf)returnf[n][m][k]; intres=inf; up(i,......
  • CF1866G
    link每个车厢的人可以到的是一段区间。题面显然提示二分答案,二分答案\(x\),每个车厢可以承受\(x\)个人,考虑如何check每个人能否都能到一个区间。有一个比较显然的网络流来check的做法,原点向每个车厢连流量\(a_i\)的边,每个车厢向自己能到的区间连边,然后每个区间再向汇点......
  • CF1874F Jellyfish and OEIS 题解
    题目链接不明白出题人的脑回路是不是被宇宙射线改变过/jy。题目给出了若干个区间,要我们计算满足每个区间都不是对应下标的排列的数量,正着计算不满足要求的数量是困难的,我们将其容斥,转化为钦定一些区间要求其必须满足它是对应下标的排列,在下文中,我们称这样的区间为一个约束。我......
  • CF1454F
    linkSoltion:有一个比较显然的\(O(n^2)\)做法,枚举中间区间的左右端点,然后用前后缀\(\max\)和st表查询中间的\(\min\),其实不用st表也行,确定左端点枚举右端点的时候顺便求一下就好。考虑枚举左端点,以一个较快的方法求出右端点。发现后缀\(\max\)和确定左端点后的\(......
  • CF1451
    CF1451SubtractorDivide显然如果为偶数那么我们将它变到\(2\)再\(-1\)即可如果为奇数我们先\(-1\)再转化为偶数的情况即可对于\(n\le3\)进行特判#include<bits/stdc++.h>usingnamespacestd;#defineendl'\n'#defineinlinline#defineebemplace_back......