A题:1165A
Input
11 5 2
11010100101
Output
1
Input
11 5 1
11010100101
Output
3
因为只关注对\(10^x\) 取模为 \(10^y\) 次方,那么我们只关注,怎么只操作n位数字的后x位,除了对倒数第y+1位要置1外,其他都置为0。我们将后y位数字里面为1的数量记录为time,如果要置1的位置的数字为0则操作数time+1,如果要置1的位置的数字位1,则重复操作,输出time-1.
#include
using namespace std;
int n, x, y, res, cnt;
string s;
int main() {
//freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> x >> y;
cin >> s;
for (int i = n - 1, cnt = 0; cnt < x; i--) {
if (cnt == y)res += s[i] != '1';
else res += s[i] != '0';
cnt++;
}
cout << res << endl;
}
B题:1165B
Input
4
3 1 4 1
Output
3
Input
3
1 1 1
Output
1
Input
5
1 1 1 2 2
Output
2
思路
这题有两个方法,看到另一个同学的方法,感觉我的有些愚钝。
第一种,则是小到大排序,然后遍历数组,每遇到能满足做题数量的比赛,则天数加一。
第二种,则是用数组来记录有n道题的比赛数量,然后遍历一次数组,算是基数排序吧。
#include
using namespace std;
int main() {
//freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0);
int n, i, p = 0;
cin >> n; int arr[n];
for (i = 0; i < n; i++)
cin >> arr[i];
sort(arr, arr + n);
for (i = 0; i < n; i++)
if (arr[i] > p)
p++;
cout << p;
}
C题:1165C
Input
4
good
Output
0
good
Input
4
aabc
Output
2
ab
Input
3
aaa
Output
3
思路
这题的方法比较贪心,我们知道像abccd这种字符串,我们只需要删一个就能变成一个好字符串。可以是ab之一,也可以是c。对于连续的重复的字符串,只要它符合好字符串的规则,也就是前一个在偶数位置,后一个在奇数位置,那么就不需要特别处理。当然多与两个便一定要删减了。
我们可以采取贪心的策略,重新组合一个字符串。当我们取奇数位置时,可以随意取,取偶数位置时候,如果和奇数位置相同,则不取。
#include
using namespace std;
int main() {
int n, i; cin >> n;
string s, ss; cin >> s;
for (i = 0; i < n - 1;) {
if (s[i] != s[i + 1]) {
ss += s[i];
ss += s[i + 1];
i += 2;
}
else i++;
}
cout << n - ss.size() << endl << ss;
}
D题:1165D
思路
模拟,利用set的性质存储输入的因子(自带排序),
排序
如果数组符合要求,那么这个X必定是最大最小值相乘可得
尝试对tmp求因子,如果所有的因子匹配上了即可输出。
#include
using namespace std;
typedef long long ll;
sets, ss;
int main() {
//freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0);
ll t, n, tmp; cin >> t;
while (t--) {
cin >> n;
s.clear(); ss.clear();
for (ll i = 1; i <= n; ++i) {
cin >> tmp;
s.insert(tmp);
}
tmp = (*s.begin()) * (*s.rbegin());
for (ll i = 2; i * i <= tmp; ++i) {
if (tmp % i == 0) {
ss.insert(i);
ss.insert(tmp / i);
}
}
if (s == ss)cout << tmp << endl;
else cout << -1 << endl;
}
}
E题:1165E
输入
5
1 8 7 2 4
9 7 2 9 3
输出
646
输入
1
1000000
1000000
输出
757402647
输入
2
1 3
4 2
输出
20
思路
我们知道,对于两个元素数量相同的数组,如何排序让它们的各位相乘求和的值最小,那么只能是
一个数组正序,一个数组倒序,然后逐个相乘求和。
对于这题,a和b只能移动b数组的顺序,那么其实是一样的,只要b第i大的数字对应a第i小的数字就
行了。但是题目给出了$ f(l,r)$这个函数,并且是所有这个函数相加。不难得到,在n个元素的数组中,对于第i个元素,必定有 $ i*(n-i+1)$个区间将这个元素包含在内,也就是说,和第 $i $个元素相关的乘积将出现以上次累加。
对于a这个数组来说,它是不能动的,何不先把这些累计的次数与a里的元素相乘呢。
我们将a内元素和对应累计次数相乘得到的新数组p 排正序,b排倒序,再逐位相乘相加,取个模,
那就是我们要求的答案了。
#include
using namespace std;
typedef long long ll;
const int MOD = 998244353;
const int N = 2e5 + 100;
ll n, ans, a[N], b[N], q[N], k;//使用long long防溢出
bool cmp(int x, int y) {
return a[x] > a[y];
}
int main() {
freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0);
cin >> n;
//对于第i个元素,必定有i*(n-i+1)个区间将这个元素包含在内
for (int i = 0; i < n; i++)cin >> a[i],a[i] *= (i + 1) * (n - i),q[i] = i;
for (int i = 0; i < n; ++i)cin >> b[i];
sort(q, q + n,cmp); sort(b, b + n);
ans = 0;
for (int i = 0; i < n; i++){
k = (a[q[i]] % MOD * b[i]) % MOD;
ans = (ans + k) % MOD;
}
cout << ans << endl;
}
F题:
CodeForces - 1165F1
F1、F2思路和AC代码 来自大牛 Jfeng666
题意
简单版和难版题目的区别只在于数据范围。
主人公Ivan,玩一个电脑游戏,包括很多微交易,可以得到让角色变得更帅的饰品,他想自己的角色看起来更酷,他想利用这些微交易得到饰品,并且他在得到所有东西后才开始玩这个游戏。
每一天早上,Ivan可以赚到游戏里一单位的burle(游戏货币)
有n种微交易,对于每一种微交易的花费,打折时每个饰品花费1单位burle,平时则花费2单位burle。对于第i个饰品,他想要进行ki次交易,订单将在晚上完成。
游戏商店有m次折扣,第j次输入(dj,tj)代表第t种商品在第d天打折。
Ivan想要尽早得到所有的物品,你的任务是计算最少经过多少时间他能买到所有想要数量的饰品,并开始游戏。
……………………有人说还是不懂我简单说下
主角想买一些东西,然后从第一天开始每天领一块钱
平时每件东西是两块,打折日对某些种类当天就一块。
给了你打折日,还有他想买的东西,给好种类和数量了
打折日也说明了日期和种类了
问你最短多少时间内能买完这些东西
思路
对于结果来说,最重要的是天数。如果主角想要n个物品,那么所需要天数必定在n~2n以内,我们只需要找到其中最小的可以买完东西的天数就行了。
对于固定的天数day,我们能接触到的打折活动必定在第day天及之前能接触到。那么对于同一件物品,打折的时间越后,能一次性买的数量越多。我们不妨在这天尽量买足所需数量。但是请注意,在第day天前举办的打折活动,并不能使用day个货币,也就是无法超前消费,那么,对于第day天剩余拥有的货币bday,和第fday天举办的活动(fday同理,对于第5天和第3天的打折,假设第五天有五个货币,为了满足需求,我买了三个,那么对于第三天的打折,我最多只能买两个,假设对这天打折的需求也是三个,那么剩余一个必定要通过两元一个的原价购买。所以这样的贪心并不影响结果。
#include
#include
using namespace std;
#define maxn 200010
//该算法对于两个范围难度的题都能解决。
int lf, rt, b[maxn];
int ned[maxn], da[maxn], tp[maxn];
int k, p[maxn], n, m;
int cmp(int x, int y) {
return da[x] < da[y];
}
int min(int a, int b) {
return a < b ? a : b;
}
bool check(int v) {//测试v块钱能否买完
for (int i = 1; i <= n; i++)
b[i] = 1;
//经过最后打折日的物品在前面打折日则不再购买,因为必定买完,或者剩下的需求没法满足
int mon = v, cost = 0;
for (int i = m; i > 0; i--)
if (b[tp[p[i]]] && da[p[i]] <= v) {
b[tp[p[i]]] = 0;
mon = min(mon, da[p[i]]);
cost += min(mon, ned[tp[p[i]]]);
mon -= min(mon, ned[tp[p[i]]]);;
} //只要低于v的折扣都能接触到,但能买的最大数量限制于打折时间和需求。
return cost + (v - cost) / 2 >= lf;
}
int divide(int lf, int rf) {
int mid;
while (lf < rf) {
mid = (lf + rf) / 2;
if (check(mid)) rf = mid - 1;
else lf = mid + 1;
}
//为了优化贪心找到答案的次数,我使用二分法。
return check(rf) ? rf : rf+1;
//因为退出循环时存在rf=lf和rf=lf-1的可能
}
int main()
{
cin >> n >> m;
lf=0;
for (int i = 1; i <= n; i++){
cin >> ned[i];
lf += ned[i];
} rt = lf * 2;
for (int i = 1; i <= m; i++) {
cin >> da[i] >> tp[i];
p[i] = i;
}
sort(p + 1, p + 1 + m, cmp);
cout << divide(lf, rt) << endl;
return 0;
}