2023牛客寒假算法基础集训营3个人补题 A B C D E F G I K

2023牛客寒假算法基础集训营3个人补题 A B C D E F G I K

A

题意

小红拿到了一个数组,她每次操作可以选择一个偶数除以2,可以操作任意次(也可以不操作)。求最终数组所有元素之和的最小值。

思路

简单贪心,所有非负偶数不断除以二就完了。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

void solve() {
  cin >> n;
  int sum = 0;
  for (int i = 1; i <= n; i++) {
    int x;
    cin >> x;
    if (x % 2 == 0 && x > 0) {
      while (x % 2 == 0) x /= 2;
    }
    sum += x;
  }
  cout << sum << "\n";
}

signed main() {
  IOS;
  int t = 1;
  // cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

B

题意

小红希望用恰好n块矩形积木来搭建正方形,其中小红可以自由选择每块积木的大小,但必须是 1 ∗ k 1*k 1k的长和宽。其中 1 ≤ k ≤ ⌈ n 2 ⌉ 1\leq k \leq \lceil \frac{n}{2} \rceil 1k2n。小红想知道,自己最大可以搭建多大的正方形?请你帮小红计算正方形的边长。如果无法用恰好n块矩形拼成正方形,请输出-1。

思路

打表找规律,先想过二分是否能做,但是没有想到check函数怎么写,最终打表加手玩分析把公式推出来了。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

void solve() {
  cin >> n;
  if(n==2) {
    cout<<"-1\n";
      return;
  }
  cout << (int)sqrt(1.0 * n * ((n - 1) / 2 + 1)) << "\n";
}

signed main() {
  IOS;
  int t = 1;
  cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

C

题意

构造一个长度为n的排列,满足对于每个 a i a_i ai,有 2 ≤ ∣ a i − i ∣ ≤ 3 2\le |a_i-i|\le 3 2aii3

思路

直接dfs爆搜,由于每次只会向下四步,所以可以保证不会超时。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

int vis[N];
bool f;
int d[]={-2,-3,2,3};
void dfs(int k) {
	if(k==n+1) {
		f=1;
		return;
	}
	for(int i=0;i<4;i++) {
		if(d[i]+k>0&&d[i]+k<=n&&vis[d[i]+k]==0) {
			vis[d[i]+k]=k;
			dfs(k+1);
            if(f) return;
			vis[d[i]+k]=0;
		}
	}
}
int res[N];
void solve() {
  cin>>n;
  dfs(1);
  if(!f) {
  	cout<<-1<<"\n";
  	return;
  }
  for(int i=1;i<=n;i++) {
  	res[vis[i]]=i;
  }
  for(int i=1;i<=n;i++) {
  	cout<<vis[i]<<" ";
  }
}

signed main() {
  IOS;
  int t = 1;
  // cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

D

题意

给定一个正整数n,小红和小紫轮流操作,每次取n的一个因子x,使得n减去x。谁先将n减到0谁输。
小红先手操作,她想知道在双方足够聪明的情况下,谁会获得最终的胜利?

思路

简单博弈,可以发现1为必赢态,然后可以用这种方法逆推转移状态,最终发现应该是直接判断数字的奇偶性。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

void solve() {
  cin>>n;
  if(n==1) {
  	cout<<"yukari\n";
  }
  else if(n==2) {
  	cout<<"kou\n";
  }
  else {
  	if(n%2) cout<<"yukari\n";
  	else cout<<"kou\n";
  }
}


signed main() {
  IOS;
  int t = 1;
  // cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

E

题意

选择了两个点A和B(保证两点不重合),它们的坐标分别为 ( x A , y A ) (x_A,y_A) (xA,yA) ( x B , y B ) (x_B,y_B) (xB,yB)。小红希望你选择一个整点C,满足三角形ABC为以AB为斜边的等腰直角三角形。

思路

思路很简单,可以使用初中学过的三垂直推公式O(1)判断,唯一麻烦的地方在于输出一定要强转为int型,卡在这里卡了半天。。。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

void solve() {
  int xa, ya, xb, yb;
  cin >> xa >> ya >> xb >> yb;
  double mx = (xa + xb) * 1.0 / 2, my = (ya + yb) * 1.0 / 2;
  if (my - xa + mx == (int)(my - xa + mx) &&
      mx - my + ya == (int)(mx - my + ya)) {
    cout << (int)(mx - my + ya) << ' ' << (int)(my - xa + mx) << "\n";
  } else if (my + xa - mx == (int)(my + xa - mx) &&
             mx + my - ya == (int)(mx + my - ya)) {
    cout << (int)(mx + my - ya) << ' ' << (int)(my + xa - mx) << "\n";
  } else
    cout << "No Answer!\n";
}
signed main() {
  IOS;
  int t = 1;
  // cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

F

题意

输出42。

思路

输出42。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

void solve() {
  string s;
  cin>>s;
  cout<<"42\n";
}

signed main() {
  IOS;
  int t = 1;
  // cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

G

题意

给定一直表达式,符号自己填,问是否有让等式成立的表达式。

思路

由于符号只有三种,所以只需要dfs暴力枚举就可以,要注意的问题在于新定义的运算要求参与运算的两个数都是正整数(因为这个卡 了半天),另外使用快速幂的时候开long long也会爆,需要开__int128。当然,取模用类似哈希的思想应该也可以,但是有可能会被卡哈希。

代码

#include <bits/stdc++.h>
#define int __int128
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];
string s;
int ans;
bool f;
vector<int> v;
vector<int> ss(20);
vector<int> q;
__int128 read(){
    __int128 x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
void print(__int128 x){
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar(x%10+'0');
}
int qpow(int a, int b, int m) {
	int ans = 1, base = a;
	while (b) {
		if (b & 1) ans = ans * base % m;
		base = base * base % m;
		b >>= 1;
	}
	return ans % m;
}
void check() {
	int res = q[0], num = 0;
	int i = 1;
	while (i < q.size()) {
		num = q[i];
		if (ss[i - 1] == 0) {
			res = num + res;
		}
		if (ss[i - 1] == 1) {
			res = res - num;
		}
		if (ss[i - 1] == 2) {
			if (num == 0||res<=0) return;
			res = qpow(res, res, num);
		}
		i++;
	}
	if (res == ans) f = 1;
	if (f) {
		int i = 0;
		while (i < q.size()) {
			print(q[i]);
			if (i < q.size()-1) {
				if (ss[i] == 0) {
					cout << "+";
				}
				if (ss[i] == 1) {
					cout << "-";
				}
				if (ss[i] == 2) {
					cout << "#";
				}
				
			}
			i++;
		}
		cout << "=" ;
        print(ans);
        cout<<"\n";
	}
}
void dfs(int k) {
	if (k == v.size()) {
		check();
		return;
	}
	for (int i = 0; i <= 2; i++) {
		ss[k]=i;
		dfs(k + 1);
		if (f) return;
	}
}
void solve() {
	cin >> s;
	int num = 0;
	for (int i = 0; s[i]; i++) {
		if (s[i] == '?')
			q.push_back(num), num = 0, v.push_back(i);
		else if (s[i] == '=') {
			q.push_back(num);
			num = 0;
		} else {
			num = num * 10 + s[i] - '0';
		}
	}
	ans = num;
	dfs(0);
	if (!f) cout << -1 << "\n";
}

signed main() {
	//IOS;
	int t = 1;
	// cin >> t;
	for (int i = 1; i <= t; i++) {
		solve();
	}
}

I

题意

定义“约和运算”:对一个不小于2的整数而言,求它的所有不等于它本身的约数之和进行的运算。
记一个整数n的“约和”为S(n)。例如,S(10)=1+2+5=8。 给一个正整数x,找到一个正整数n满足S(n)=x。

思路

被E卡太久了最后看榜去开K了,没有发现I很简单,我们可以分类讨论,当x为奇数的时候,因为有一个数是1,所以剩下的我们假设能由一个或两个质数组成,然后预处理 1 0 6 10^6 106内质数然后枚举就可以了,至于为什么,就是哥德巴赫猜想了();偶数的时候由于保证了x-1和x-3至少有一个为质数,当x-3为质数的时候 ( x − 1 ) / d o t 2 (x-1)/dot 2 x1/dot2一定满足条件,x-1为质数的时候 ( x − 1 ) 2 (x-1)^2 (x1)2一定满足条件。唯一的坑就是在小数值的时候x=7需要特判一下,因为存在偶质数数2,使得8满足条件。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

int primes[N], cnt;  // primes[]存储所有素数
bool st[N];          // st[x]存储x是否被筛掉

void get_primes(int n) {
  for (int i = 2; i <= n; i++) {
    if (!st[i]) primes[cnt++] = i;
    for (int j = 0; primes[j] <= n / i; j++) {
      st[primes[j] * i] = true;
      if (i % primes[j] == 0) break;
    }
  }
}
void solve() {
  cin >> n;
    int x=n;
    if (x == 7) 
        cout << 8 << "\n";
  else if (n % 2 == 0) {
    if (n - 3 > 0 && !st[n - 3]) {
      cout << (n-3)*2 << "\n";
    } else if (n - 1 > 0 && !st[n - 1])
      cout << (n - 1) * (n - 1) << "\n";
    else
      cout << -1 << "\n";
  } else {
    n--;
          if(!st[n]) {
    	cout<<n*n<<"\n";
    	return;
    }
    for (int i = 0; i < cnt; i++) {
      if (n - primes[i] > 0 && !st[n - primes[i]] &&
          n - primes[i] != primes[i]) {
        cout << primes[i] * (n - primes[i]) << "\n";
        return;
      }
    }
    cout << -1 << "\n";
  }
}

signed main() {
  IOS;
  int t = 1;
  cin >> t;
  st[1] = 1;
  get_primes(N);
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

K

题意

给定指定质数,要求将其进行排列,使得前i( 1 ≤ i ≤ n 1 \le i \le n 1in)个数相乘的约束个数之和最大。

思路

有点绕,感觉就是找规律。然后差分前缀和求每个因数出现的次数,最后枚举再用推出的公式使用等比数列求解。

代码

#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
using namespace std;
typedef pair<int,int>PII;
const int N = 2e5+10,mod=1e9+7;
int a[N],s[N];
int qmi(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}
int get(int x)
{
    return (x%mod+mod)%mod;
}
void solve()
{
   int n;
   scanf("%lld",&n);
   for(int i=1;i<=n;i++)
   {
       int x;
       scanf("%lld",&x);
       s[x+1]--,s[0]++;
   }
   for(int i=1;i<=2e5;i++)  s[i]=s[i-1]+s[i];
   int ans=0,res=1;
   for(int i=1;i<=2e5;i++)
   {
       int q = (i+1)*qmi(i,mod-2)%mod;
       ans=get(ans+res*q%mod*get(qmi(q,s[i])-1)%mod*qmi(get(q-1),mod-2)%mod);
       res=res*qmi(q,s[i])%mod;
   }
   cout<<ans<<endl;
    
}
signed main()
{
    int T=1;
    //cin>>T;
    while(T--)
    {
        solve();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值