2018 ACM-ICPC, Syrian Collegiate Programming Contest F. Pretests(子集dp)
发布日期:2021-06-30 10:32:37 浏览次数:2 分类:技术文章

本文共 1238 字,大约阅读时间需要 4 分钟。

题意

一道题有 k k k个测试点,共提交了 n n n

每次提交是一个长为 k k k 01 01 01串,表示是否能通过第 i i i个测试点

现在要求你重新排序 k k k个测试点,使得 ∑ i = 1 n w [ i ] \sum\limits_{i=1}^nw[i] i=1nw[i]最小

其中 w [ i ] w[i] w[i]指的是第 i i i个人第一次在第几个测试点 w r o n g   a n s w e r wrong\ answer wrong answer

输出字典序最小的方案数


考虑定义 f [ i ] f[i] f[i]表示当放置测试点状态为 i i i时,能得到的最小代价

那么枚举本次放的是第 j j j道题,放置之后由状态 v v v转移到状态 u u u

造成的代价是 n u m ( u ) num(u) num(u)( u u u的二进制位是 1 1 1的个数,表示在这个测试点 w a wa wa掉)

因为在之前的 n u m ( u ) − 1 num(u)-1 num(u)1个测试点都没有 w a wa wa掉,在第 n u m ( u ) num(u) num(u)个测试点 w a wa wa

我们需要求满足要求的提交个数也就是 u u u的超集,再减去 v v v的超集,那么计算出这次转移的代价 v a l val val

f [ u ] = m i n ( f [ u ] , f [ v ] + v a l ) f[u]=min(f[u],f[v]+val) f[u]=min(f[u],f[v]+val)

记录一个前驱就可以转移了

#include 
using namespace std;const int maxn = 2e6+10;const int inf = 1e9;int t,n,T,num[maxn],pre[maxn],cnt[maxn],f[maxn],bit[maxn];string s[maxn];void sosdp(){
for(int i=1;i<=n;i++) cnt[num[i]]++; for(int i=0;i
=0;i--) {
for(int j=1;j<=t;j++)//枚举每一个测试点 {
if( i&(1<<(j-1)) ) {
int v = i ^ (1<<(j-1)), val = f[i] + ( cnt[v]-cnt[i] )*bit[i]; if( val
>1] + (i&1); cin >> T; while( T-- ) {
cin >> t >> n; for(int i=1;i<=n;i++) {
cin >> s[i]; int x = 0; for(int j=0;j

转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/116131881 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:2018 ccpc final G. Pastoral Life in Stardew Valley(组合数学)
下一篇:gym101237 C. The Palindrome Extraction(SAM+manecher)

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月27日 01时39分50秒