首页 > 其他分享 >Dual(构造)

Dual(构造)

时间:2023-08-15 23:55:56浏览次数:32  
标签:10 12 20 14 构造 Dual 15 array

题目描述

Popskyy & tiasu - Dual

[Popskyy & tiasu - Dual](https://soundcloud.com/popskyy/popskyy-tiasu-dual)

The only difference between the two versions of this problem is the constraint on the maximum number of operations. You can make hacks only if all versions of the problem are solved.

You are given an array $ a_1, a_2,\dots, a_n $ of integers (positive, negative or $ 0 $ ). You can perform multiple operations on the array (possibly $ 0 $ operations).

In one operation, you choose $ i, j $ ( $ 1 \leq i, j \leq n $ , they can be equal) and set $ a_i := a_i + a_j $ (i.e., add $ a_j $ to $ a_i $ ).

Make the array non-decreasing (i.e., $ a_i \leq a_{i+1} $ for $ 1 \leq i \leq n-1 $ ) in at most $ 31 $ operations. You do not need to minimize the number of operations.

输入格式

Each test contains multiple test cases. The first line contains the number of test cases $ t $ ( $ 1 \le t \le 500 $ ). The description of the test cases follows.

The first line contains a single integer $ n $ ( $ 1 \le n \le 20 $ ) — the length of the array.

The second line contains $ n $ integers $ a_1, a_2, \ldots, a_n $ ( $ -20 \le a_i \le 20 $ ) — the array before performing the operations.

输出格式

For each test case, output your operations in the following format.

The first line should contain an integer $ k $ ( $ 0 \le k \le 31 $ ) — the number of operations.

The next $ k $ lines represent the $ k $ operations in order. Each of these $ k $ lines should contain two integers $ i $ and $ j $ ( $ 1 \leq i, j \leq n $ ) — the corresponding operation consists in adding $ a_j $ to $ a_i $ .

After all the operations, the array $ a_1, a_2,\dots, a_n $ must be non-decreasing.

提示

In the first test case, by adding $ a_1 = 2 $ to $ a_2 $ , we get the array $ [2, 3] $ which is non-decreasing.

In the second test case, the array changes as:

- $ [1, 2, -10, 3] $
- $ [1, 2, -10, 6] $
- $ [1, 2, -10, 12] $
- $ [1, 2, 2, 12] $

In the third test case, the final array is $ [2, 3, 3, 3, 3] $ .

输入输出样例

输入 #1
10
2
2 1
4
1 2 -10 3
5
2 1 1 1 1
8
0 0 0 0 0 0 0 0
5
1 2 -4 3 -10
10
11 12 13 14 15 -15 -16 -17 -18 -19
7
1 9 3 -4 -3 -2 -1
3
10 9 8
20
1 -14 2 -10 6 -5 10 -13 10 7 -14 19 -5 19 1 18 -16 -7 12 8
20
-15 -17 -13 8 14 -13 10 -4 11 -4 -16 -6 15 -4 -2 7 -9 5 -5 17
输出 #1
1
2 1
3
4 4
4 4
3 4
4
2 1
3 1
4 1
5 1
0
7
3 4
3 4
5 4
5 4
5 4
5 4
5 4
15
6 1
6 1
6 1
7 2
7 2
7 2
8 3
8 3
8 3
9 4
9 4
9 4
10 5
10 5
10 5
8
3 4
3 4
2 4
2 4
2 4
2 4
1 4
1 4
3
2 1
3 1
3 1
31
14 1
18 7
13 11
15 11
6 4
5 17
19 6
19 12
10 5
11 12
1 17
15 19
16 10
14 2
16 11
20 7
7 6
9 5
3 6
6 14
17 18
18 14
12 3
17 16
8 18
13 16
9 8
14 8
16 2
11 8
12 7
31
5 12
19 13
9 1
5 17
18 19
6 16
15 8
6 9
15 14
7 10
19 7
17 20
14 4
15 20
4 3
1 8
16 12
16 15
5 6
12 10
11 15
20 3
20 19
13 14
11 14
18 10
7 3
12 17
4 7
13 2
11 13

说明/提示

In the first test case, by adding 1=2a1​=2 to 2a2​ , we get the array [2,3][2,3] which is non-decreasing.

In the second test case, the array changes as:

  • [1,2,−10,3][1,2,−10,3]
  • [1,2,−10,6][1,2,−10,6]
  • [1,2,−10,12][1,2,−10,12]
  • [1,2,2,12][1,2,2,12]

In the third test case, the final array is [2,3,3,3,3][2,3,3,3,3] .

 

贪心地去想,我们一定尽可能让每次走的次数都具有价值。现在这样想,如果数组之内的正数多,那么我们让一个最大的数自增,增到什么程度呢?直到我们能把数组内的所有数变成正数为止。相反,如果负数多,那么我们把所有的数变为负数。显而易见,有一个规律:如果全部是正数,那么我们只需要用后一个数加上前一个数就可以了。

由于次数限制是 $31$ 次,我们每次相加需要消耗 $19$ 次。那么留给我们全部置负或者正的次数为 $12$ 次。如果正数多,就按正数来;如果负数多,就按负数来。这里注意,如果此时数组里只有 $1$ 和 $-20$,那么我们的 $1$ 需要自增 $5$ 次才够。显然不如直接用 $-20$ 来得快,可以省去这 $5$ 次。相同地,如果我们的正负数之差小于 $5$,可以按照其相反的次序来。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;

const int N=1e6+10,mod=1e9+7;  // 定义常量 N 和 mod,用于数组大小和取模运算
string s;  // 未使用,字符串变量 s
int n,t,a[N],res,num,ans,m,k_z,k_f;  // 定义各种整数变量和数组
int z,f,f_num,z_num,f_sum,z_sum;  // 定义整数变量,用于记录正数和负数的数量及和
int maxx,minn,max_id,min_id;  // 定义整数变量和索引,用于记录数组的最大和最小值的位置
int cnt1[N],cnt2[N];  // 计数数组,用于记录操作次数
map<int,pair<int,int>>mp1,mp2;  // map 容器,用于记录操作的位置

bool vis[N];  // 布尔数组,未使用

// 处理正数情况的函数
void solve_z()
{
        minn=abs(minn);
        // 通过操作,将最小负数变为正数的绝对值
        while(a[max_id]<minn) res++,a[max_id]+=a[max_id],z_num++;
        res+=(n-1);
        // 将其他负数变为正数
        for(int i=1;i<=n;i++) if(a[i]<0) res++,cnt1[i]++,mp1[i]={i,max_id},a[i]+=a[max_id];
        cout<<res<<endl;
        // 输出操作次数和具体操作的位置
        while(z_num!=0) z_num--,cout<<k_z<<" "<<k_z<<endl;
        for(int i=1;i<=n;i++) while(cnt1[i]!=0) cnt1[i]--,cout<<mp1[i].first<<" "<<mp1[i].second<<endl;
        for(int i=1;i<=n-1;i++) cout<<i+1<<" "<<i<<endl;
}

// 处理负数情况的函数
void solve_f()
{
        while((-a[min_id])<maxx) a[min_id]+=a[min_id],res++,f_num++;
        res+=(n-1);
        // 将其他正数变为负数
        for(int i=1;i<=n;i++) if(a[i]>0) res++,cnt1[i]++,mp1[i]={i,min_id},a[i]+=a[min_id];
        cout<<res<<endl;
        // 输出操作次数和具体操作的位置
        while(f_num!=0) f_num--,cout<<k_f<<" "<<k_f<<endl;
        for(int i=1;i<=n;i++) while(cnt1[i]!=0) cnt1[i]--,cout<<mp1[i].first<<" "<<mp1[i].second<<endl;
        for(int i=n;i>=2;i--) cout<<i-1<<" "<<i<<endl;
}

// 主处理函数
void solve()
{
    cin>>n;  // 输入数组长度
    z=f=num=res=ans=m=z_num=f_num=z_sum=f_sum=0;
    mp1.clear();  // 清空 map 容器
    memset(cnt2,0,sizeof cnt2);  // 初始化计数数组
    a[0]=-30,maxx=-30,minn=30;  // 初始化数组和最大最小值
    for(int i=1;i<=n;i++){
        cin>>a[i];  // 输入数组元素
        if(a[i]>0) z++,z_sum+=a[i];  // 统计正数个数和和
        else if(a[i]==0) ;  // 不处理为零的情况
        else f++,f_sum+=a[i];  // 统计负数个数和和
        if(maxx<a[i]) maxx=a[i],max_id=i,k_z=i;  // 更新最大值和位置
        if(minn>a[i]) minn=a[i],min_id=i,k_f=i;  // 更新最小值和位置
    }
    // 根据正数和负数的数量及和进行处理
    if(z>f)
        if(z_sum<abs(f_sum)&&abs(z-f)<=5)
            solve_f();
        else
            solve_z();
    else{
        if(z_sum>abs(f_sum)&&abs(z-f)<=5)
            solve_z();
        else
            solve_f();
    }
}

signed main()
{
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>t;  // 输入测试用例数量
    while(t--){
        solve();  // 处理每个测试用例
    }
    return 0;
}

 

标签:10,12,20,14,构造,Dual,15,array
From: https://www.cnblogs.com/o-Sakurajimamai-o/p/17632775.html

相关文章

  • java中对无参构造和有参构造的理解
    构造器的最大作用就是在创建对象时,对对象实例进行初始化。1.一个类即使什么都不写,也会存在无参构造方法。2.无参构造方法没有返回值类型,且方法名称和类名相同。比如:1publicclassStudent{2privateStringname;3privateintage;45publicvoidst......
  • Codechef - N Triplets(构造+观察)
    题目大意  对于一个正整数N,需要找到三个不同的数字A,B,C,使得三个数当中任意两个数字相乘都是N的约数,另外还要使得A,B,C三个数字乘积是N的整数倍数。最后输出三个数字(如果有多种组合,输出任意一种即可),如果找不到满足条件的则输出-1。 思路  注意到1必然是其中一个约数,另外我们......
  • 【C++ Primer读书笔记】7.1.4 构造函数
    构造函数构造函数的任务是初始化类对象的数据成员被调用的时机,无论何时只要类的对象被创建,就会调用构造函数构造函数的特殊性1.构造函数与类名称相同2.构造函数没有返回值3.构造函数不能被声明为const,因为当我们创建一个const对象时,直到构造函数完成初始化过程,对象才......
  • golang 构造函数的应用
    在Go语言中,没有类似于传统面向对象编程语言中的构造函数的概念。然而,你可以使用初始化函数来达到类似的效果。在Go中,结构体(struct)是一种用于封装一组相关字段的数据类型。你可以为结构体定义一个初始化函数,该函数在创建结构体实例时自动调用,用于设置字段的初始值。这个初始化函数......
  • 6529: 构造完全图 最小生成树
    描述 对于完全图G,若有且仅有一棵最小生成树为T,则称完全图G是树T的扩展出的。给你一棵树T,找出T能扩展出的边权和最小的完全图G。 输入 第一行N表示树T的点数。接下来N-1行:Si,Ti,Di;描述一条边(Si,Ti)权值为Di。保证输入数据构成一棵树。对于20%的数据,N<=10对于50%的......
  • [Unity]为什么不要在Unity中使用构造函数
    MonoBehaviour派生出来的类会作为Unity3D中的Component挂载在GameObject上,而GameObject会在编辑器的多个地方被显示,如场景编辑器内、Prefab选中时等,这些时候都需要调用它们的构造函数来初始化成员变量的默认值,以便在编辑器中显示它们,也就是说,构造函数的调用次数和调用时机是“完全......
  • C++ 构造函数初始化:提高代码可读性和执行效率
    在C++中,构造函数是用来初始化对象数据成员的。一个对象在创建的时候,构造函数会被自动调用,以便为该对象的数据成员赋初值。传统的初始化方式是在构造函数内部对数据成员逐一进行初始化,这种方式虽然可行,但是代码复杂度高且效率低下。本文将介绍如何使用构造函数初始化列表来提高......
  • 构造完全图
    题目描述对于完全图G ,若有且仅有一棵最小生成树T ,则称完全图G 是树T 扩展出的。给你一棵树T ,找出T 能扩展出的边权和最小的完全图G。输入格式第一行正整数N  表示树T 的点数;接下来N-1 行三个整数u,v,w ;描述一条边 (u,v) 权值为w;保证输入数据......
  • 软件测试|什么是Python构造方法,构造方法如何使用?
    构造方法(Constructor)是面向对象编程中的重要概念,它在创建对象时用于初始化对象的实例变量。在Python中,构造方法是通过特殊的名称__init__()来定义的。本文将介绍Python构造方法的基本概念、语法和用法。什么是构造方法?在面向对象编程中,构造方法是一个特殊的方法,用于在创建对象时初......
  • 前端原型和原型链构造函数的使用
     目录前言导语代码部分 总结代码部分 总结前言我是歌谣我有个兄弟巅峰的时候排名c站总榜19叫前端小歌谣曾经我花了三年的时间创作了他现在我要用五年的时间超越他今天又是接近兄弟的一天人生难免坎坷大不了从头再来歌谣的意志是永恒的放弃很容易但是坚持一定很酷导语......