第一题:支付宝活动
在线测评链接:http://121.196.235.151/p/P1137
题目描述
众所周知,在一些消费支付的场合中,往往有“支付宝九五折”的优惠。这天薯条哥来到了超市购买物品,一共有nnn种物品,每种物品只能购买一个,但有的物品支持优惠活动,有的并不支持。恰好本超市的结账是有“支付宝九五折”优惠的,薯条哥的支付宝余额还剩kkk元,他想知道他仅使用支付宝进行支付的话最多能买几件物品?
输入描述
输入包含三行。
第一行两个正整数n,k(≤n≤105),(1≤k≤109)n,k(\le n\le 10^5),(1\le k\le 10^9)n,k(≤n≤105),(1≤k≤109)
第二行包含nnn个正整数ai(1≤ai≤104)a_i(1\le a_i\le 10^4)ai(1≤ai≤104)表示每个物品的价格。
第三行一个长度为nnn的只含有0和1的字符串,表示每个物品是否支持优惠。(如果是1代表第iii个物品支持优惠,否则不支持。)
输出描述
输出一行一个整数表示答案
样例
输入
3 975
1000 500 500
0 0 1
输出
2
思路:贪心+排序
首先,我们可以计算打折商品打折后的价格,计算好之后,将所有商品按照价格从小到大排序,然后枚举即可,直到枚举到钱不够的情况,停止枚举,输出答案。
注意:本题需要使用double
存储,否则会丢失精度导致计算结果不正确
C++
#include <bits/stdc++.h>
using namespace std;
using namespace std;
const int N=1e5+10;
int n;
double a[N],k;
string s;
int main() {
cin>>n>>k;
for(int i=0;i<n;i++)cin>>a[i];
cin>>s;
for(int i=0;i<n;i++){
if(s[i]=='1'){
a[i]*=0.95; //计算打折后的价格
}
}
sort(a,a+n);
int ans=0;
double sum=0;
for(int i=0;i<n;++i){
sum+=a[i];
if(sum<=k) ans++;
else break;
}
cout<<ans<<endl;
return 0;
}
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
double k = scanner.nextDouble();
double[] a = new double[n];
for (int i = 0; i < n; i++) {
a[i] = scanner.nextDouble();
}
String s = scanner.next();
for (int i = 0; i < n; i++) {
if (s.charAt(i) == '1') {
a[i] *= 0.95; // 计算打折后的价格
}
}
Arrays.sort(a);
int ans = 0;
double sum = 0;
for (int i = 0; i < n; ++i) {
sum += a[i];
if (sum <= k) ans++;
else break;
}
System.out.println(ans);
}
}
Python
n, k = map(int, input().split())
a = list(map(float, input().split()))
s = input()
for i in range(n):
if s[i] == '1':
a[i] *= 0.95
a.sort()
ans = 0
sum = 0
for price in a:
sum += price
if sum <= k:
ans += 1
else:
break
print(ans)
第二题:元辅音方案数
在线测评链接:http://121.196.235.151/p/P1138
题目描述
ak机定义一个字符串的权值是:字符串辅音数量和元音数量的差的绝对值。
例如,“arcaea"的权值是 2,因为有4个元音,2 个辅音权值为∣4−2∣|4-2|∣4−2∣=2.现在ak机拿到了一个字符串,她想把这个字符串切成两个非空字符串,需要满足两个字符串的权值相等。ak机想知道,有多少种不同的切割方式?我们定义,元音有"aeiou"这五种,其余字母均为辅音,
输入描述
一个仅包含小写字母的字符串,长度不超过2×1052\times 10^52×105
输出描述
切割方案数。
样例
输入
arcaea
输出
2
思路:前缀和
我们可以使用前缀和数组pre1,pre2pre1,pre2pre1,pre2分别统计前iii个字符中的元音数量和辅音数量
当我们枚举到位置iii时,我们可以根据前缀和数组计算出左边子串的元音数量和辅音数量c1,c2c1,c2c1,c2,
其中c1=pre1[i]−pre1[0],c2=pre2[i]−pre2[0]c1=pre1[i]-pre1[0],c2=pre2[i]-pre2[0]c1=pre1[i]−pre1[0],c2=pre2[i]−pre2[0]
然后再拿总的元音数量和辅音数量计算出右半边对应的数量c3,c4c3,c4c3,c4
如果有∣c1−c2∣=∣c3−c4∣|c1-c2|=|c3-c4|∣c1−c2∣=∣c3−c4∣,则答案+1。
本题我们可以一边枚举一边计算,可以用c1,c2c1,c2c1,c2这两个变量来代替前缀和数组,有点类似前后缀分解的思想。
C++
#include<bits/stdc++.h>
using namespace std;
const int N=2E5+10;
string s;
int w[N],S[N];
int main(){
cin>>s;
int n=s.size();
set<char>st={'a','e','i','o','u'};
int cnt1=0,cnt2=0;
for(int i=0;i<n;i++){
if(st.count(s[i])){
cnt1++;
}
else{
cnt2++;
}
}
int c1=0,c2=0,res=0;
for(int i=0;i<n;i++){
if(st.count(s[i])){
c1++;
}
else{
c2++;
}
int c3=cnt1-c1,c4=cnt2-c2;
if(abs(c1-c2)==abs(c3-c4)){
res++;
}
}
cout<<res<<endl;
return 0;
}
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
int n = s.length();
Set<Character> st = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u'));
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < n; i++) {
if (st.contains(s.charAt(i))) {
cnt1++;
} else {
cnt2++;
}
}
int c1 = 0, c2 = 0, res = 0;
for (int i = 0; i < n; i++) {
if (st.contains(s.charAt(i))) {
c1++;
} else {
c2++;
}
int c3 = cnt1 - c1, c4 = cnt2 - c2;
if (Math.abs(c1 - c2) == Math.abs(c3 - c4)) {
res++;
}
}
System.out.println(res);
}
}
Python
s = input()
n = len(s)
st = {'a', 'e', 'i', 'o', 'u'}
cnt1, cnt2 = 0, 0
for char in s:
if char in st:
cnt1 += 1
else:
cnt2 += 1
c1, c2, res = 0, 0, 0
for char in s:
if char in st:
c1 += 1
else:
c2 += 1
c3, c4 = cnt1 - c1, cnt2 - c2
if abs(c1 - c2) == abs(c3 - c4):
res += 1
print(res)
第三题:变化数组
在线测评链接:http://121.196.235.151/p/P1139
题目描述
薯条哥有一个长度为nnn 的数组aaa。他想要使得所有aia_iai 的最大公因子是一个素数。即gcd(a1,a2...,an)gcd(a_1,a_2...,a_n)gcd(a1,a2...,an)是一个素数。他可以对数组进行任意次操作。
具体的:每次操作,他会选择i,ji,ji,j两个下标,同时执行:ai=ai+2,aj=aj−2a_i= a_i+2,a_j=a_j-2ai=ai+2,aj=aj−2
请问他是否有可能在任意次操作内将数组变成符合要求的。如果可以,请输出所有可能的最大公因数。
注意,这里要保证aja_jaj在操作后仍然是正数,即不能选择aj≤2a_j\le 2aj≤2
输入描述
输入包含两行。
第一行一个正整数n(2≤n≤2×105)n(2 ≤n≤2\times 10^5)n(2≤n≤2×105)表示数组长度。
第二行 nnn个正整数ai(1≤ai≤106)a_i(1\le a_i\le 10^6)ai(1≤ai≤106)表示这个数组
输出描述
输入包含一行或两行。
如果可以输出“YES”否则输出“NO”(不含双引号)
如果答案为“YES”,则第二行按照升序输出所有可行的数组 gcd.
样例1
输入
4
1 3 5 9
输出
YES
3
说明
可以选择一次i=1,j=3i= 1,j=3i=1,j=3,这样一来数组变成:
[3,3,3,9][3,3,3,9][3,3,3,9], gcd=3。gcd =3。gcd=3。
可以证明只有 3这一个答案
样例2
输入
4
2 2 2 2
输出
YES
2
思路:数论+分类讨论
首先观察可知,操作有两个特点
- 不会改变元素的奇偶性,奇数操作完了还是奇数,偶数亦然
- 不会改变数组的元素总和,总和sumsumsum是一个固定值
那么我们首先考虑一种极端情况:数组所有元素都是偶数,那么一定有且仅有一个公素数:2,不会存在其他素数了,因此直接输出2即可
本题有一个重要结论,任何奇数/偶数,都可以通过+2、-2来变成任意一个奇数/偶数。
对于数组中又有奇数,又有偶数的情况,我们可以枚举总和sumsumsum的素因子(素因子一定是奇数,唯一的偶数素因子就是2,2不可能满足条件)
我们可以枚举所有素因子xxx,对于枚举到的素因子xxx,对于数组中的所有奇数,其值至少要等于xxx,或者就等于2x,3x,...2x,3x,...2x,3x,...
对于数组中的所有偶数,其值至少要等于2x2x2x,或者就等于4x,6x,...4x,6x,...4x,6x,...
因此一定要满足下面三个条件
条件1:xxx是sumsumsum的因子
条件2:x×(n+cnt)≤sumx\times (n+cnt)\le sumx×(n+cnt)≤sum,其中cntcntcnt为数组中偶数的数量(因为偶数至少要为2x2x2x)
条件3:x>2x>2x>2,因为数组里面有奇数,因此xxx一定是奇素数
按照上述方式统计素因子即可
C++
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N],n;
long long sum;
int main() {
cin>>n;
int cnt=0; //记录数组中偶数的个数
for(int i=0;i<n;i++){
cin>>a[i];
sum+=a[i];
if(a[i]%2==0){
cnt++;
}
}
if(cnt==n){ //如果数组中所有的数字都是偶数,有且仅有一个公共素因子:2
puts("YES");
puts("2");
return 0;
}
vector<int>res; //记录所有合法的素因子
long long total=sum;
for(long long i=2;i*(n+cnt)<=total;i++){
if(sum%i==0&&i!=2){
res.push_back(i);
}
while(sum%i==0){ //去除sum中所有i的因子,类似质因数分解的思想
sum/=i;
}
}
if(!res.size())puts("NO");
else{
puts("YES");
for(int &x:res){
cout<<x<<" ";
}
}
return 0;
}
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] a = new int[n];
long sum = 0;
int cnt = 0; // 记录数组中偶数的个数
for(int i = 0; i < n; i++){
a[i] = scanner.nextInt();
sum += a[i];
if(a[i] % 2 == 0){
cnt++;
}
}
if(cnt == n){ // 如果数组中所有的数字都是偶数,有且仅有一个公共素因子:2
System.out.println("YES");
System.out.println("2");
return;
}
List<Integer> res = new ArrayList<>(); // 记录所有合法的素因子
long total = sum;
for(long i = 2; i * (n + cnt) <= total; i++){
if(sum % i == 0 && i != 2){
res.add((int)i);
}
while(sum % i == 0){ // 去除sum中所有i的因子,类似质因数分解的思想
sum /= i;
}
}
if(res.isEmpty()){
System.out.println("NO");
} else {
System.out.println("YES");
for(int x : res){
System.out.print(x + " ");
}
}
}
}
Python
n = int(input())
a = list(map(int, input().split()))
sum = 0
cnt = 0 # 记录数组中偶数的个数
for i in range(n):
sum += a[i]
if a[i] % 2 == 0:
cnt += 1
if cnt == n: # 如果数组中所有的数字都是偶数,有且仅有一个公共素因子:2
print("YES")
print("2")
else:
res = [] # 记录所有合法的素因子
total = sum
i = 2
while i * (n + cnt) <= total:
if sum % i == 0 and i != 2:
res.append(i)
while sum % i == 0: # 去除sum中所有i的因子,类似质因数分解的思想
sum /= i
i += 1
if not res:
print("NO")
else:
print("YES")
print(" ".join(map(str, res)))