zoukankan      html  css  js  c++  java
  • 「CF1521E」Nastia and a Beautiful Matrix

    • 题目大意

      你有 (k) 个数字,他们分别是 (1,2,3,...,k) 对于数字 (i) 你有相同的 (a_i)​ 个。

      定义一个 (n imes n) 的矩阵为美丽矩阵:

      • 这个 (n imes n) 的矩阵包含了你所拥有的所有数字;

      • 对于每个 (2 imes 2) 的子矩阵,占用的格子不能超过 (3)(当一个格子的数为 (0) 时,我们认为它没有被占用)并且每个对角线的数字是不同的;

      现在,你要构造一个最小的美丽矩阵。


    • 分析

      首先,考虑每个 (2 imes2) 矩阵都必须有一个 (0) ,不妨先计算出最少需要几个 (0)

      显然,对于每个 ((i+j) equiv 0 pmod{2})(i)(j) 都为偶数时候,把 ((i,j)) 赋值为 (0) ,此时的 (0) 数量最少。

      所以最少需要的 (0) 的个数是 (leftlfloor dfrac{p}{2} ight floor ^2)

      所以在算 (p) 的时候,最小的 (p) 一定要满足 (m>p^2-leftlfloor dfrac{p}{2} ight floor ^2)

      接着我们对 (0) 的上下左右染色,上下为 (1) ,左右为 (2)

      因为 (0) 此时已经满足题目要求了。所以我们考虑对角线要求。

      此时只要考虑每组的 (1)(2) 不同就好了。

      但是,有可能此时染色无法满足要求。如果出现一个颜色的数量大于白色和 (0) (或 (1) )的总数,就无法满足要求。

      但这种颜色最多存在 (1) 个,所以开头计算 (p) 的时候再多判断一下就好了。

      如果保证一定有解,那就直接染色就好了。把 (cnt_i) 从小到大排序,(0) 从数量最小的颜色开始赋值,(1) 从最大的开始赋值。注意这里的赋值包括 (0) ,也优先考虑 (0) 。可以证明这样一定满足题目要求。

    • 代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N=1e5+5,M=3000+5;
    struct node{
    	int id,x;
    }cnt[N];
    int T,n,m,p,a[M][M],ans[M][M];
    bool cmp(node u,node v)
    {	if(u.x!=v.x)return u.x<v.x;
    	else return u.id<v.id;
    }
    void solve()
    {	
    	cnt[0].x=p*p-m;cnt[0].id=0;
    	for(int i=1;i<=p;i++)
    		for(int j=1;j<=p;j++)
    			a[i][j]=-1;
    	for(int i=1;i<=p;i++)
    		for(int j=1;j<=p;j++)
    		{	
    			if((i&1)==0&&(j&1)==0&&((i+j)&1)==0)
    			{	
    				a[i][j]=ans[i][j]=0;
    				cnt[0].x--;
    				a[i-1][j]=a[i+1][j]=1;
    				a[i][j-1]=a[i][j+1]=2;
    			}
    		}
    	int x=0,y=n;
    	while(x<=n&&cnt[x].x==0)x++;
    	while(y>=0&&cnt[y].x==0)y--;
    	for(int i=1;i<=p;i++)
    		for(int j=1;j<=p;j++)
    		{	
    			if(a[i][j]==0)continue;
    			else if(a[i][j]==1)
    			{	
    				ans[i][j]=cnt[x].id;
    				cnt[x].x--;
    				while(x<=n&&cnt[x].x==0)x++;
    			}
    			else if(a[i][j]==2)
    			{	
    				ans[i][j]=cnt[y].id;
    				cnt[y].x--;
    				while(y>=0&&cnt[y].x==0)y--;
    			}
    		}
    	for(int i=1;i<=p;i++)
    		for(int j=1;j<=p;j++)
    		{	
    			if(a[i][j]!=-1)continue;
    			ans[i][j]=cnt[x].id;
    			cnt[x].x--;
    			while(x<=n&&cnt[x].x==0)x++;
    		}
    }
    int main()
    {	
    	scanf("%d",&T);
    	while(T--)
    	{	
    		scanf("%d%d",&m,&n);
    		for(int i=1;i<=n;i++)
    		{	
    			scanf("%d",&cnt[i].x);
    			cnt[i].id=i;
    		}
    		sort(cnt+1,cnt+1+n,cmp);
    		if(m==1)
    		{	
    			printf("1
    %d
    ",cnt[n]);
    			continue;
    		}
    		p=2;
    		while(p*p-(p/2)*(p/2)<m)p++;
    		while(cnt[n].x>p*p-(p/2)*(p/2)-(p/2)*((p+1)/2))p++;
    		solve();
    		printf("%d
    ",p);
    		for(int i=1;i<=p;i++)
    		{	
    			for(int j=1;j<=p;j++)
    				printf("%d ",ans[i][j]);
    			printf("
    ");
    		}
    	}
    	return 0;
    }
    

    [ ext{by Rainy7} ]

  • 相关阅读:
    小M和天平(简单DP)
    前缀查询(维护字典树前缀和)
    假的字符串( trie树 + 拓扑)
    E. Two Teams(线段树+链表)
    B. Ugly Pairs(简单dfs)
    回文(牛客 https://ac.nowcoder.com/acm/problem/17062)
    Dubbo中CompletableFuture异步调用
    Dubbo消费者异步调用Future使用
    Dubbo消费者异步调用Future使用
    Dubbo服务暴露延迟
  • 原文地址:https://www.cnblogs.com/Rainy7/p/cf1521e-solution.html
Copyright © 2011-2022 走看看