在牛客上做了2021的4星和2星编程题。
晚上应该是寄了,然后总结一下。
3月4号的题,写个大概,应该是要保密的。
1.序列排列组合,需要排个序。a[i]!=i。
2.没看懂。
3.做n个题,然后需要多少天做完,要求一天多一天少。
从牛客上找的。
1完美对
输入描述:
第一行两个数字n,k。 接下来n行,第i行k个数字表示。
输出描述:
一行一个数字表示答案
输入例子1:
5 3 2 11 21 19 10 1 20 11 1 6 15 24 18 27 36
输出例子1:
3
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,k;
cin >> n >> k;
vector<vector<int>> q(n,vector<int>(k));
/*两个序列是不是完美对,关键在于它们的差分序列是否互为相反数。
已知序列a,统计它的完美对个数,只需要查询其余序列即可。*/
for(int i=0;i<n;i++)
for(int j=0;j<k;j++)
cin>>q[i][j];
int cnt = 0;
unordered_map<string, int> hash;//为了方便查询。将序列b的差分序列转成string,以1个key查询。
for(int i=0;i<n;i++){
string diffa = "";//序列a 的差分
string diffA = "";//序列a的完美对 的差分。
for(int j=0;j<k-1;j++){
int tmpDa = q[i][j] - q[i][j+1];
int tmpDA = q[i][j+1] - q[i][j];
diffa += tmpDa>=0 ? "+" + to_string(tmpDa) : to_string(tmpDa);//主要是为了分割数字,.正数加+号,负数
//自带-号
diffA += tmpDA>=0 ? "+" + to_string(tmpDA) : to_string(tmpDA);
}
if(hash.find(diffA) != hash.end()) //如果找到了
cnt += hash[diffA];//diffa的完美对
hash[diffa]++;//序列a也是某个序列的完美对,+1
}
cout <<cnt <<endl;
return 0;
}
//牛客347830471号
sync_with_stdio 是输入同步开关:(7条消息) sync_with_stdio_底层码农-CSDN博客_sync_with_stdio
2选择物品
输入例子1:
4 1
输出例子1:
1 2 3 4
输入例子2:
5 2
输出例子2:
1 2 1 3 1 4 1 5 2 3 2 4 2 5 3 4 3 5 4 5
#include<iostream>
#include<vector>
using namespace std;
void dfs(vector<int>&temp, int n, int m, int index){
if (temp.size() == m){
//输出temp
for (int i = 0; i < temp.size(); i++){
if (i == 0) cout << temp[i];
else cout << " " << temp[i];
}
cout << endl;
return;
}
else{
for (int i = index; i <= n; i++){
temp.push_back(i);
dfs(temp, n, m, i + 1);
temp.pop_back();
}
}
}
int main(){
int n, m;
while (cin >> n >> m){
vector<int> temp;
dfs(temp,n,m,1);
}
return 0;
}
//来自 <https://www.nowcoder.com/test/question/done?tid=52828485&qid=1664933#summary>
3小强去春游
输入例子1:
2 4 2 10 12 11 4 2 3 7 8
输出例子1:
37 19
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,t,a[100005];
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int i,j;
cin>>t;
while(t--)
{
cin>>n;
for(i=1; i<=n; i++)
cin>>a[i];
sort(a+1,a+n+1);
ll ans=0;
while(n>=4)
{
ans+=min(a[1]*2+a[n-1]+a[n],a[1]+2*a[2]+a[n]);
n-=2;
}
if(n==3)
ans+=a[1]+a[2]+a[3];
else if(n==2)
ans+=a[2];
else if(n==1)
ans+=a[1];
cout<<ans<<endl;
}
return 0;
}
大佬 零葬 分享了解题思路。零葬的个人主页_牛客网 (nowcoder.com)
剩余人数不少于4的时候,比较如下两种操作方案看哪一种用时更少:
1.最轻的人由重到轻每次带过去一个人然后开船回来(为了和方案2对齐,每次也只运2个人);
2.最轻和次轻的过去,然后最轻的回来让最重的两个过去,次轻的在那边把船再开回来。一共运过去了2个人。
这样一来,人数少于4的时候要么只有最轻的3个人,要么只有最轻的2个人。如果还剩3个人,就让最轻的每次带一个;如果还剩2个人,就直接两个人过河了。
c++代码来自 寒冰-侠客
---
--
4比例问题
输入例子1:
1 1 2 1
输出例子1:
0 0
输入例子2:
1000 500 4 2
输出例子2:
1000 500
输入例子3:
1000 500 3 1
输出例子3:
999 333
#include<iostream>
#include<vector>
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
typedef unsigned int u8;
ll A,B,a,b;
int MaxFactor(ll a,ll b)
{
ll c=b;
while(a%b!=0)
{
c=a%b;
a=b;
b=c;
}
return c;
}
int main()
{
cin>>A>>B>>a>>b;
int MaxCom=MaxFactor(a,b);
int simp_a=a/MaxCom,simp_b=b/MaxCom;
int k;
if((b*A)/(a*B)) k=B/simp_b;
else k=A/simp_a;
u8 x=k*simp_a;
u8 y=k*simp_b;
cout<<x<<" "<<y<<endl;
return 0;
}
5小强修水渠
输入例子1:
4 0 0 0 50 50 50 50 0
输出例子1:
100
例子说明1:
当修建水渠位置的直线方程为x=0或者x=50时,都能获得最小距离和.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//1.题目的答案其实和x轴的坐标无关系,只需要考虑y轴的数据;
//2.在输入数据的时候,是先输入的y,再输入x;
//3.假如只有两座房子,它们在y方向的距离为length,水渠只要在这两个端点之间(包括端点),所得到的距离总和就是最短的,
//为length,如果水渠在两个端点之外,那就不行;
//4.对所有的纵坐标从小到大排序,把最外侧的两个点找出来,它俩到水渠的距离之和为(y[n-1] - y[0]),水渠在它俩之间;
//接着考虑第2个数和倒数第2个数,水渠应该调整到它俩之间去,这样它俩到水渠的距离之和为(y[n-2] - y[1]);
//水渠的位置调整后,并不违背之前所做的工作,因为水渠的位置还是在第1个值和最后那个值之间;
//同理考虑第3组,。。。。这一步完成后,水渠的位置在第3组数之间,同样在第2组数之间,因为第3组数在第2组数的内侧
//5.最后的结果要把所有的差值加起来,注意要声明为long long类型;
//6.每次操作的是两个数,如果数的总数是奇数个呢?最中间那个可以不考虑,因为可以把水渠选在这个值上
void solve(int n)
{
vector<int> nums(n, 0);
for (int i = 0; i < n; ++i)
{
int x = 0;
cin >> nums[i] >> x; //先输入y,再输入的x,真是干tn的
}
sort(nums.begin(), nums.end()); //排序
int p1 = 0;
int p2 = n - 1;
long long ans = 0;
while(p1 < p2) //从两端往中间收缩
{
ans += nums[p2] - nums[p1]; //保存一组结果
++p1;
--p2;
}
cout << ans << endl;
}
int main()
{
int n = 0;
cin >> n;
solve(n);
return 0;
}
6国际交流会
输入例子1:
4 3 6 2 9
输出例子1:
20 6 2 9 3
例子说明1:
这么坐的话 差异和为|6-2|+|2-9|+|9-3|+|3-6|=20为最大的情况。
输入例子1:
5 5 9 5 4 4 4 7 4 10 3 2 10 9 2 3
输出例子1:
5
例子说明1:
数组b可以为[5,7,5,4,4],答案为5。
#include<iostream>
#include<algorithm>
#include<vector>
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
ll Abs(ll a,ll b)
{
if(a>=b) return a-b;
else return b-a;
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0);
int n,p1,p2,index;
ll ans=0;
cin>>n;
ll a[n];
vector<ll> tmp;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n); //smaller--->larger
if(n%2==0) p2=n/2;
else p2=n/2+1;
p1=0;//最左边
index=p2;//中间
while(p1<index && p2<n)
{//从最左边和最中间,向右移动
tmp.push_back(a[p1]);
p1+=1;
tmp.push_back(a[p2]);
p2+=1;
}
if(p1<index) tmp.push_back(a[p1]);
for(int i=0;i<n-1;i++)
{
ans+=Abs(tmp[i],tmp[i+1]);
}
ans+=Abs(tmp[0],tmp[n-1]);
cout<<ans<<endl;
for(int i:tmp)
{
cout<<i<<" ";
}
cout<<endl;
return 0;
}
7小强的神奇矩阵
#include <iostream>
#include <vector>
using namespace std;
void solution(int n)
{
vector<vector<int>> nums(3,vector<int>(n, 0));
for (int i = 0; i < 3; ++i)
for (int j = 0; j < n; ++j)
cin >> nums[i][j];//读数据
vector<vector<long long>> dp(3, vector<long long>(n, 0));
for (int j = 1; j < n; ++j) {
for (int i = 0; i < 3; ++i) {
//分别取0、1、2行的时候,值是多少。
//当它减去nums[0][j-1]的时候,就要继承dp[0][j-1]这个状态。
long long f1 = abs(nums[i][j] - nums[0][j - 1]) + dp[0][j - 1];
long long f2 = abs(nums[i][j] - nums[1][j - 1]) + dp[1][j - 1];
long long f3 = abs(nums[i][j] - nums[2][j - 1]) + dp[2][j - 1];//状态
dp[i][j] = min(min(f1, f2), f3);//状态
}
}
cout << min(min(dp[0][n - 1], dp[1][n - 1]), dp[2][n - 1]) << endl;
}
int main()
{
int n = 0;
cin >> n;
solution(n);
return 0;
}
8蚂蚁森林之王
输入例子1:
4 0 1 1 1
输出例子1:
4 1 1 1
例子说明1:
如果第 2,3,4 只小动物均和第一只投一样的票,则第一只小动物可以获得四票。
#include<iostream>
#include<vector>
using namespace std;
void func(){
int n;
cin>>n;
vector<int> A(n+1);
vector<int> num(n+1,1);//全是1
for(int i=1;i<=n;i++){
cin>>A[i];
}
for(int i=n;i>=1;i--){//最多得到能力相同的票
num[A[i]] += num[i];//和崇拜的对象投相同票
}
for(int i=1;i<=n;i++){//每个人最多几票。
cout<<num[i]<<endl;//最弱只可能自己1票
}
}
int main(){
func();
return 0;
}
9删除字符
输入例子1:
2 5 2 abcab 10 4 lkqijxsnny
输出例子1:
aab ijsnny
同样是大佬零葬的解答:
要想字典序小,那么字符串中的字母应该尽可能满足升序。因此只需遵循一个原则,当前字母的ASCII码不能比前面字母的小,如果出现这种情况,就要把前面的字母删除掉,从当前字母重新开始算字符串。最后需要注意,返回的字符串长度应该为n-m。
#include<bits/stdc++.h>
using namespace std;
int main(){
int T;
cin>>T;
while(T--){
int n,m;
cin>>n>>m;
string in;
cin>>in;
stack<char> tmp;
int deleteNumber = 0;
for (int i = 0;i<in.length();i++){
char x = in[i];
//当前的x小于栈顶,则弹出栈顶。如果还小,则再弹出栈顶。
while(!tmp.empty() && x<tmp.top() && deleteNumber<m){
tmp.pop();
deleteNumber++;
}
tmp.push(x);
}
string result;
while(!tmp.empty()){
result+=tmp.top();//栈内元素倒出来。
tmp.pop();
}
reverse(result.begin(),result.end());//反向
cout<<result.substr(0,n-m)<<endl;//输出
}
return 0;
}
10视力表
输入例子1:
2 3 1 0 0
输出例子1:
4
例子说明1:
共有如下四种情况
上上 上上
上下 下上
上下 下上
上上 上上
输入例子2:
2 2 1 1 0
输出例子2:
12
输入例子3:
2 1 1 1 1
输出例子3:
24
这道题通过暴力法能通过。
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include <cstdlib>
#include <climits>
#include <ctype.h>
#include<functional>
using namespace std;
const int maxn = 1e5 + 5;
typedef long long int ll;
int n, a, b, c, d;
const int MOD = 998244353;
ll f[maxn], inv[maxn];//f存储i阶乘,inv存储(i阶乘)的逆元
//
ll Pow(ll x, ll t)
{
ll cnt = 1;
while (t)
{
if (t & 1)//x&1是判断x是奇数还是偶数,如果x是奇数那么x&1的值就是true,如果x是偶数那么x&1的值就是false
cnt = cnt*x%MOD;
x = x * x %MOD;
t >>= 1;
}
return cnt;
}
void init()
{
cin >> n >> a >> b >> c >> d;
n = n*n;
f[0] = 1;
for (int i = 1;i <= n;i++)
f[i] = i*f[i - 1] % MOD;
//a的逆元 = a^(p-2) mod p
inv[0] = 1;
inv[n] = Pow(f[n], MOD - 2);
//inv[i]=inv[i+1]*(i+1)
for (int i = n-1;i >= 1;i--)
inv[i] = inv[i + 1] * (i + 1) % MOD;
}
int main()
{
init();
ll ans = f[n];
//cout << f[n] << ' ' << inv[a] << ' ' << inv[b] << ' ' << inv[c] << ' ' << inv[d] << '\n';
//for (int i = n;i >= 1;i--)
// cout << inv[i] << ' ';
//cout << endl;
ans = ans*inv[a] % MOD;
ans = ans*inv[b] % MOD;
ans = ans*inv[c] % MOD;
ans = ans*inv[d] % MOD;
cout << ans << '\n';
}
/*
3 7 1 0 1
*/