首页 > 其他分享 >P7450 [THUSCH2017] 巧克力

P7450 [THUSCH2017] 巧克力

时间:2023-10-14 09:12:27浏览次数:35  
标签:巧克力 int pc while rg gc P7450 THUSCH2017 define

P7450 [THUSCH2017] 巧克力

题意

给定一张网格图,每个格子有两个权重,\((a,c)\),我们希望找出一个不包含 \(c=-1\) 的联通块并且 \(a\) 的中位数最大,同时还要包含 \(k\) 种颜色。

题解

套路题都是nb题。

首先 \(k\) 比较小,我们可以考虑一个类似斯坦纳树的 \(dp\)。
\(f_{i,j,S}\) 表示以 \((i,j)\) 为 根,满足状态有 \(S\) 的最小联通块大小。
需要注意的是这里是点的贡献不是边的贡献,所以在枚举子集转移的时候要减去当前根的重复贡献
但是我们并不知道 \(k\) 个颜色是哪 \(k\) 个颜色,考虑随机化将所有颜色重新分配成 \([1,k]\) 种颜色。
若最优解中的 \(k\) 种颜色被赋上的颜色互不相同则就能算出正确答案,容易分析得正确的概率为 \(\frac{k!}{k^k}\),多随机几百次就可以了。
然后考虑如何和解决中位数,考虑二分,将价值转为 \(-1,1\) 的样子,求和为负数的连通块。

注意到这样不太好满足联通块最小的条件
有一个很厉害的做法,将 \(-1\) 改为 \(9999\),\(1\) 改为 \(10001\),求出来的答案比最小连通块的 \(1000\) 倍小说明合法。
正确性显然,实际上类似于给大小和中位数上一个优先级,在满足大小最小的前提下再令和最小。,可能也有其它做法,但是我觉得这个处理方法还是很妙的。

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define rg register
#define pc putchar
#define gc getchar
#define pf printf
#define space pc(' ')
#define enter pc('\n')
#define me(x,y) memset(x,y,sizeof(x))
#define pb push_back
#define FOR(i,k,t,p) for(rg int i(k) ; i <= t ; i += p)
#define ROF(i,k,t,p) for(rg int i(k) ; i >= t ; i -= p)
using namespace std ;
bool s_gnd ;
inline void read(){}
template<typename T,typename ...T_>
inline void read(T &x,T_&...p)
{
    x = 0 ;rg int f(0) ; rg char c(gc()) ;
    while(!isdigit(c)) f |= (c=='-'),c = gc() ;
    while(isdigit(c)) x = (x<<1)+(x<<3)+(c^48),c = gc() ;
    x = (f?-x:x) ;
    read(p...);
}
int stk[30],tp ;
inline void print(){}
template<typename T,typename ...T_>
inline void print(T x,T_...p)
{
    if(x < 0) pc('-'),x = -x ;
    do stk[++tp] = x%10,x /= 10 ; while(x) ;
    while(tp) pc(stk[tp--]^48) ; space ;
    print(p...) ;
}
bool S_GND ;
const int K = 6 ;
const int N = 240 ;
const int INF = 1e9+7 ;
int n,k,m,T,top ;
int col[N*N],f[N][N][1<<K] ;
int a[N][N],w[N][N],c[N][N],now[N],vis[N][N] ;
int fx[10][10] = {{0,1},{1,0},{-1,0},{0,-1}} ;
mt19937 rd(19260817) ;
void SPFA(int S)
{
    queue<pii>q ; //cerr<<"!" ;
    FOR(i,1,n,1) FOR(j,1,m,1) if(f[i][j][S] != INF) q.push({i,j}),vis[i][j] = 1 ;
    while(!q.empty())
    {
        auto [x,y] = q.front() ; q.pop(),vis[x][y] = 0 ;
        FOR(k,0,3,1)
        {
            int X = x+fx[k][0],Y = y+fx[k][1] ;
            if(X < 1 || Y < 1 || X > n || Y > m || c[X][Y] == -1) continue ; //assert(w[X][Y] > 0) ; 
            if(f[X][Y][S] > f[x][y][S]+w[X][Y]) 
            {
           // print(S,f[x][y][S],f[X][Y][S],w[X][Y]),enter ;
                f[X][Y][S] = f[x][y][S]+w[X][Y] ;
                if(!vis[X][Y]) q.push({X,Y}),vis[X][Y] = 1 ;
            }
        }
    } 
}
int solve()
{
    int res = INF ;
    FOR(QAQ,1,200,1)
    {
        shuffle(col+1,col+top,rd) ;
        FOR(i,1,n,1) FOR(j,1,m,1) FOR(S,0,(1<<k)-1,1) f[i][j][S] =  INF ;
        FOR(i,1,top,1) if(~col[i]) now[col[i]] = i%k ;
        FOR(i,1,n,1) FOR(j,1,m,1) if(~c[i][j]) f[i][j][1<<now[c[i][j]]] = w[i][j] ;
        FOR(S,0,(1<<k)-1,1) 
        {
            for(int T = S&(S-1) ; T ; T = (T-1)&S) FOR(i,1,n,1) FOR(j,1,m,1) if(~c[i][j])
                f[i][j][S] = min(f[i][j][S],f[i][j][T]+f[i][j][S^T]-w[i][j]) ; SPFA(S) ;
        }
        FOR(i,1,n,1) FOR(j,1,m,1) if(~c[i][j]) res = min(res,f[i][j][(1<<k)-1]) ; 
    }
    return res ;
}
void Solve()
{
    read(n,m,k),top = 0 ;
    FOR(i,1,n,1) FOR(j,1,m,1) read(c[i][j]) ;
    FOR(i,1,n,1) FOR(j,1,m,1) read(a[i][j]) ; //cerr<<"!" ;
    FOR(i,1,n,1) FOR(j,1,m,1) col[++top] = c[i][j],w[i][j] = 1 ;
    sort(col+1,col+1+top),top = unique(col+1,col+1+top)-col-1 ; //cerr<<"!" ;
    int sz = solve(),le = 1,ri = 1e6,res = 0 ; //cerr<<"!" ;
    if(sz == INF){print(-1,-1),enter ; return ;}
    while(le <= ri)
    {
        int mid = le+ri>>1 ;
        FOR(i,1,n,1) FOR(j,1,m,1) w[i][j] = a[i][j]<=mid?9999:10001 ;
        int num = solve() ; if(num <= sz*10000) ri = mid-1,res = mid ; else le = mid+1 ;
    }
    print(sz,res),enter ;
}
signed main()
{
//cerr<<(double)(&s_gnd-&S_GND)/1024.0/1024.0 ;
//	freopen(".in","r",stdin) ;
//	freopen(".out","w",stdout) ;
    read(T) ; while(T--) Solve() ;
    return 0 ;
}

标签:巧克力,int,pc,while,rg,gc,P7450,THUSCH2017,define
From: https://www.cnblogs.com/snow-panther/p/17763675.html

相关文章

  • [THUSCH2017] 大魔法师 卡题记录
    题目:fzqoj-luogu前情提示: 此题极度卡常!!!,否则你就会像我这个蒟蒻一样卡题\(3h\):死亡记录前置知识:  1.线段树的区间修改,不会的可以点这-基础:进阶  2.基本的矩阵乘法:Fibonacci题解部分对于题目给出的6种操作,我们可以用线段树与矩阵乘法来维护思路维护一个四......
  • 蓝桥杯 分巧克力
    https://www.lanqiao.cn/problems/99/learning/?page=3&first_category_id=1&sort=students_count&second_category_id=3暴力方法N,K=map(int,input().split())chocolates=[[int(n)fornininput().split()]for_inrange(N)]max_size=1forsizei......
  • P9387 [THUPC 2023 决赛] 巧克力 题解
    这篇题解会只讲怎么dp,所以我们这里跳过博弈论的部分。Let'srephrasetheproblemstatementasfollows:给定\(n,m\),设\(x=1\oplus2\oplus\cdots\oplusn\oplusm\)。求有多少个有序三元组\((a,b,c)\)满足:\(a+b+c\len\)或\(a+b+c=m\)(如果都满足需要算两遍)。\((a+b......
  • 【算法题】2706. 购买两块巧克力
    题目:给你一个整数数组prices,它表示一个商店里若干巧克力的价格。同时给你一个整数money,表示你一开始拥有的钱数。你必须购买恰好两块巧克力,而且剩余的钱数必须是非负数。同时你想最小化购买两块巧克力的总花费。请你返回在购买两块巧克力后,最多能剩下多少钱。如果购买任意......
  • P8647 [蓝桥杯 2017 省 AB] 分巧克力
    P8647[蓝桥杯2017省AB]分巧克力暴力做法(60分)#include<bits/stdc++.h>usingnamespacestd;constintN=1e5+10;inta[N],b[N];intn,k,sum;booljudge(intx){//倍数判断intans=0;for(inti=0;i<n;i++){intx1=a[i]/x;inty......
  • 黎明前的巧克力
    刚考完省选回来的时候搬的模拟赛的题。看到一道长的很类似的题所以把题解蒯过来。首先对于每个异或和为\(0\)的子集\(T\),贡献为\(2^{|T|}\)。答案就是把他们加起来然后减掉\(1\),是两个都不选的。那么有一个浅显的dp:\(dp_{i,j}\)为考虑前\(i\)个元素,异或和为\(j\)的贡......
  • 「解题报告」UOJ310 黎明前的巧克力
    我还是太不懂FWT了!首先发现,两个人的集合异或和相等,那么这两个人的集合的并的异或和等于\(0\),而相对应地,每一个大小为\(k\)的异或和为\(0\)的集合都有\(2^k\)种方案。那么我们实际上就是要找所有异或和等于\(0\)的方案数。考虑集合幂级数刻画,那么我们要求的就是\(n\)......
  • 分巧克力
    分巧克力蓝桥杯分巧克力思路:发现可以分的块数是由(Hi/a)*(Wi/a)得来,a正方形边长(原理:"/"自动向下取整)观察数据量,10^5时间2s可以用二分来枚举正方形可能的边数写一个check函数,对长度合理的边进行处理publicclassN99{ staticintN=100010;//多......
  • 分巧克力 | 二分
      P8647[蓝桥杯2017省AB]分巧克力-洛谷|计算机科学教育新生态(luogu.com.cn)一图说清下述两种代码孰对孰错的原因:  错误代码:#include<iostream>#include<algorithm>#include<cmath>usingnamespacestd;#defineios_base\ios::sync_with_stdio(f......
  • 分巧克力(二分法)
    题目描述儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。小明一共有N块巧克力,其中第i块是Hi×Wi的方格组成的长方形。为了公平起见,小明需要从这N块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:形状是正方形,边长是整数;......