zoukankan      html  css  js  c++  java
  • CodeForces 1024C. Array Product(模拟)(分类讨论)

    题意:给定一个长度为n(2 <= n <= 3e5)的数组(a[i](-1e9 <= a[i] <= 1e9)),n和a[i]都是整数。你的任务是留下一个可以尽可能最大的数字。你可以进行n - 1次下面的操作直到留下一个最大的数字
    操作1:选择一对下标(i, j)满足(1 <= i, j <= n, i != j)。j位置上的数变成了i位置和j位置上的数的乘积,(a[j] = a[j] * a[i]),并且i位置上的数被删除。

    操作2:选择一个位置i,把位置i上的数字删除(i位置的数不复存在,以后的操作中无法被选中)。操作2最多一次

    输出一个可行的方案即可。

    分析:分类讨论,这道题我写复杂了,我把所有的情况都列举出来。但是有一种更好的分类方法,如下:

    [有0\ 负数有奇数个:将绝对值最小的负数和0全部乘到一起,最后删掉0\ 负数有偶数个:将0全部乘到一起,删掉0,其它数全都乘起来\ 没有0\ 负数有奇数个:将绝对值最小的负数删掉\ 负数有偶数个:不删,其它数全都乘起来\ ]

    ps:对于一些删除容器中的操作,我们可以用一个数组标记哪些数被删除了(懒标记)。如果我们想用一个数组中指定的数,我们可以再开一个容器保存要用的数的下标。

    我的复杂代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    const int N = 300005;
    const int inf = 0x3f3f3f3f;
    int a[N];
    int main()
    {
    	//有正数
    	bool flag1 = false;
    	//有负数
    	bool flag2 = false;
    	//有零
    	bool flag3 = false;
    	//负数的个数
    	int cnt = 0;
    	//绝对值最小的负数,它的坐标
    	int mx = inf, pos = 0;
    	//存储正数、负数、零的坐标
    	vector<int> p1, p2, p3;
    	int n;
    	scanf("%d", &n);
    	for (int i = 1; i <= n; ++i)
    	{
    		scanf("%d", &a[i]);
    		if (a[i] > 0) flag1 = true, p1.push_back(i);
    		if (a[i] < 0)
    		{
    			flag2 = true, p2.push_back(i), ++cnt;
    			if (mx > abs(a[i]))
    			{
    				mx = abs(a[i]), pos = i;
    			}
    		}
    		if (a[i] == 0) flag3 = true, p3.push_back(i);
    	}
    
    	//只有0
    	if (!flag1 && !flag2 && flag3)
    	{
    		for (int i = 0; i < p3.size() - 1; ++i)
    			printf("1 %d %d
    ", p3[i], p3[i + 1]);
    	}//只有正数
    	else if ((flag1 && !flag2 && !flag3))
    	{
    		for(int i = 0; i < p1.size() - 1; ++i)
    			printf("1 %d %d
    ", p1[i], p1[i + 1]);
    	}//只有正数和0
    	else if ((flag1 && !flag2 && flag3))
    	{
    		for(int i = 0; i < p3.size() - 1; ++i)
    			printf("1 %d %d
    ", p3[i], p3[i + 1]);
    		printf("2 %d
    ", p3[p3.size() - 1]);
    		for (int i = 0; i < p1.size() - 1; ++i)
    			printf("1 %d %d
    ", p1[i], p1[i + 1]);
    	}
    	else
    	{
    		int leftpos = -1;
    		//奇数个负数
    		if (cnt & 1)
    		{
    			vector<int> p4;
    			for (int i = 0; i < p2.size(); ++i)
    				if (p2[i] != pos) p4.push_back(p2[i]);
    			if (cnt != 1)
    			{
    				for (int i = 0; i < p4.size() - 1; ++i)
    					printf("1 %d %d
    ", p4[i], p4[i + 1]);
    				leftpos = p4[p4.size() - 1];
    			}
    		}
    		else
    		{			
    			for (int i = 0; i < p2.size() - 1; ++i)
    				printf("1 %d %d
    ", p2[i], p2[i + 1]);
    			leftpos = p2[p2.size() - 1];
    		}
    		//只有负数
    		if (!flag1 && !flag3)
    		{
    			if (cnt & 1) printf("2 %d
    ", pos);
    		}
    		else
    		{
    			//有负数有正数有0
    			if (flag1 && flag3)
    			{
    				if (cnt & 1)
    				{
    					for (int i = 0; i < p3.size() - 1; ++i)
    						printf("1 %d %d
    ", p3[i], p3[i + 1]);
    					printf("1 %d %d
    ", pos, p3[p3.size() - 1]);
    					printf("2 %d
    ", p3[p3.size() - 1]);
    					if(leftpos != -1)
    						printf("1 %d %d
    ", leftpos, p1[0]);
    					for (int i = 0; i < p1.size() - 1; ++i)
    						printf("1 %d %d
    ", p1[i], p1[i + 1]);
    				}
    				else
    				{
    					for (int i = 0; i < p3.size() - 1; ++i)
    						printf("1 %d %d
    ", p3[i], p3[i + 1]);
    					printf("2 %d
    ", p3[p3.size() - 1]);
    					if(leftpos != -1)
    						printf("1 %d %d
    ", leftpos, p1[0]);
    					for (int i = 0; i < p1.size() - 1; ++i)
    						printf("1 %d %d
    ", p1[i], p1[i + 1]);
    				}
    			}//有负数和0
    			else if (!flag1 && flag3)
    			{
    				if (cnt & 1)
    				{
    					int leftzero;
    					for (int i = 0; i < p3.size() - 1; ++i)
    						printf("1 %d %d
    ", p3[i], p3[i + 1]);
    					leftzero = p3[p3.size() - 1];
    					printf("1 %d %d
    ", pos, leftzero);
    					if(cnt != 1)
    						printf("2 %d
    ", leftzero);
    				}
    				else
    				{
    					for (int i = 0; i < p3.size() - 1; ++i)
    						printf("1 %d %d
    ", p3[i], p3[i + 1]);
    					if(cnt != 0)
    						printf("2 %d
    ", p3[p3.size() - 1]);
    				}
    			}//有负数和正数
    			else
    			{
    				if (cnt & 1)
    				{
    					printf("2 %d
    ", pos);
    					if (leftpos != -1)
    					{
    						printf("1 %d %d
    ", leftpos, p1[0]);
    					}				
    					for (int i = 0; i < p1.size() - 1; ++i)
    						printf("1 %d %d
    ", p1[i], p1[i + 1]);
    				}
    				else
    				{
    					if (leftpos != -1)
    					{
    						printf("1 %d %d
    ", leftpos, p1[0]);
    					}
    					for (int i = 0; i < p1.size() - 1; ++i)
    						printf("1 %d %d
    ", p1[i], p1[i + 1]);
    				}
    
    			}
    		}
    	}
    
    	return 0;
    }
    
    
  • 相关阅读:
    swift开发之--可选类型说明,类型判断 is 与类型转换 as
    壹佰文章最全总结| 《关于ASP.NETCore的分享之路》
    Blog.Core 项目已完成升级.NET5.0
    BCVP,想真正为社区做努力的开发者们
    centos7 安装 certbot 动态更新Let's encrypt 证书实现nginx免费ssl证书
    CentOS 7.5 安装 CDH6.3.2
    cloud-init在centos中关于静态ip和hostname的配置
    wait为什么要在同步块中使用? 为什么sleep就不用再同步块中?
    Java字节码技术 static、final、volatile、synchronized关键字的字节码体现 转
    说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景 转
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/13282908.html
Copyright © 2011-2022 走看看