文章目录
#题目
##A.造数
##D 小蓝的二进制询问 有时间再写
##F 两难抉择新编 有时间再写
##H 两难抉择
##I 除法移位
##K 图上计数(Easy)
##A.造数
###题目描述
给定一个整数 n ,你可以进行以下三种操作
操作1: +1
操作2; +2
操作3: ×2
问最少需要多少次操作可以将 0 转为为 n 。
输入描述:
输入包含 1行一个整数 𝑛(0≤𝑛≤10^9)
n(0≤n≤10^9 )。
输出描述:输出包含一行一个整数,表示造出 n 所需的最小操作次数。
示例1
输入
2
输出
1
示例2
输入
5
输出
3
###思路:倒着考虑,1,2需要注意,其他就是技术减1,偶数除以2
#include <iostream>
using namespace std;
int main() {
long long n;
cin >> n;
int count = 0;
if(n==1)
{
cout<<"1";
return 0;
}
while (n > 1) //比如2的时候如果是大于0,它除以而等于1,还会进行一步,答案就不对,我当时就烦了这个错误
{
if (n % 2 == 0)
n /= 2;
// else if (n >= 3 && (n - 1) % 4 == 0)这个是当时写的,不加这个也对
// n--;
else
n--;//注意一下奇数就行
count++;
}
cout << count << endl;
return 0;
}
##D 小蓝的二进制询问 有时间再写
##F 两难抉择新编 有时间再写
链接:https://ac.nowcoder.com/acm/contest/86639/H
来源:牛客网
##H 两难抉择
###题目描述
现在有长度为n 的数组a,你可以在两种操作中选择一种进行最多一次操作。
操作1:选择一个数 i(1≤i≤n) 使得 𝑎𝑖:=𝑎𝑖+𝑥,x 可以是[1,n] 范围内任意正整数。
操作2:
选择一个数 i (1≤i≤n) 使得 𝑎𝑖:=𝑎𝑖×𝑥,x 可以是 [1,𝑛] 范围内任意正整数。
请问进行操作后,最大的数组总和是多少?
输入描述:
输入包含两行.第一行一个正整数 n (1≤𝑛≤2×10^5) 表示数组 a 的长度。
第二行
n 个正整数 ai (1≤𝑎𝑖≤10^9 ) 表示数组 a 的元素。
输出描述:
输出包含一行一个整数,表示最大的数组总和。
示例1
输入
5
5 3 4 1 2
输出
35
说明
选择第一个数
5 , 5∗5后使得数组总和最大,25+3+4+1+2=35。
###思路:就考虑两种情况,第一种就是全是1,这个时候就是+,当不是全都是1的时候就乘
#include <iostream>
#include <algorithm>
using namespace std;
long long a[200000];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
sort(a, a + n);
long long sum = 0;
for (int i = 0; i < n; i++)
sum += a[i];
long long maxSum = 0;
maxSum = max(maxSum, (long long)a[n - 1] * n + sum - a[n - 1]);
if (a[n - 1] == 1)
{
long long ans = n;
for (int i = 0; i < n ; i++)//刚开始这里到n-1,有点粗心。
ans += a[i];
maxSum = max(maxSum, ans);
}
else
maxSum = max(maxSum, sum);
cout << maxSum << endl;
return 0;
}
下面官方的比较简练
#include "bits/stdc++.h"
using namespace std;
int main()
{
int n;
cin >> n;
long long mx = 0, sum = 0;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
sum += a[i];
}
for (int i = 1; i <= n; i++)
{
mx = max({mx, sum - a[i] + 1ll * a[i] * n, sum - a[i] + a[i] + n});
}
cout << mx << '\n';
}
##I 除法移位
链接:https://ac.nowcoder.com/acm/contest/86639/I
来源:牛客网
###题目描述
现在有长度为 n 的数组 a,式子 S 定义为 𝑆=𝑎1÷𝑎2÷𝑎3…÷𝑎𝑛S=a1 ÷a2 ÷a3 …÷an ,最多对数组 a 进行 t 次循环右移操作。
请问,进行第几次操作时使得 S 最大?若存在多种答案,请输出最小值。
循环右移:一次操作使数组从 𝑎1,𝑎2,𝑎3,…,𝑎𝑛形式转换为 𝑎𝑛,𝑎1,𝑎2,…,𝑎𝑛−1 形式。
输入描述:
输入包含两行.第一行一个正整数 n,t (1≤𝑛≤2×105,0≤𝑡≤109)(1≤n≤2×105,0≤t≤109) 表示数组 a 的长度和最多的操作次数。
第二行 n 个正整数 ai(1≤𝑎𝑖≤109)(1≤a i ≤109 ) 表示数组 a 的元素。
输出描述:
输出包含一行一个整数,表示使得
S 最大的最小操作次数。
示例1
输入
5 10
5 3 4 1 2
输出
0
说明
操作0次时使得 𝑆=5÷3÷4÷1÷2
S=5÷3÷4÷1÷2 最大
备注:÷ 是正常除法,不是向上取整或向下取整。
###思路:找到可移动次数内最大数就行
#include<iostream>
#include<algorithm>
using namespace std;
long long a[200001],b[200001];
int main()
{
int n;
long long t;
cin>>n>>t;
int ans=0;
for(int i=0;i<n;i++)
cin>>a[i];
int y;
if(t>n)
y=n;//超过数组之后多余的移动没用
else
y=t;
long long maxx=a[n-1];
for(int i=n-1;i>=n-y;i--)//注意这里,刚开始我i>=n-y-1,用下面的的样例证明是错的
maxx=max(maxx,a[i]);
// cout<<maxx<<endl;
for(int i=n-1;i>=0;i--)
{
if(ans==t)//达到次数直接退出
break;
ans++;
// cout<<ans<<endl;
if(a[i]==maxx)
break;
}
b[0]=a[0];//先保存第一个数
sort(a,a+n);
if(b[0]==a[n-1])//找到的最大数如果与第一个数相同,直接输出0;
cout<<"0";
else
cout<<ans;
return 0;
}
// 5 3
// 3 4 1 2 1
##K 图上计数(Easy)
链接:https://ac.nowcoder.com/acm/contest/86639/K
来源:牛客网
###题目描述
Easy 版本和 Hard 版本唯一的区别是 Hard 版本删除的是桥,而 Easy 版本删除的是任意边。你有一张 n 个点 m 条边的无向图,你有无数次删除操作来删除任意条边以获得若干个联通块。定义联通块的大小为其所包含点个数。定义这个图的代价是:你有任意次操作,每次操作合并两个联通块,合并后联通块大小为二者之和,最后剩下两个联通块大小的乘积为此图的代价,若只有一个则代价为0。你需要最大化此图代价。
输入描述:
第一行包含两个整数 n 和 m ,图中顶点的数量和边的数量。接下来的每 m 行包含两个整数 u 和 v ,表示图中顶点 u 和 v 之间有一条无向边。(0<n≤10 6 ) (0≤𝑚≤106) (0<u,v≤n)
输出描述:
输出一个整数表示最大代价。
示例1
输入
4 3
1 2
2 3
3 4
输出
4
###思路:消除所有边,最后两个数相乘,当两个数最接近的时候就是最大值
#include<iostream>
using namespace std;
signed main()
{
long long n,m;
cin>>n>>m;
if(n%2==0)
cout<<(n/2)*(n/2);//偶数
else
cout<<(n/2+1)*(n/2);//奇数
return 0;
}