本文已参与[新人创作礼]活动,一起开启掘金创作之路
题目描述
这是4月6日代码源div1的每日一题。
Ayoub's function - 题目 - Daimayuan Online Judge
题目描述
定义函数 f(s) ,s为01字符串,f(s)为字符串s中至少包含一个1的子串数量
现在存在一字符串s,给出字符串长度 n ,和它包含的1的数量 m , 求最大的可能的 f(s)
输入格式
输入由多组测试数据组成
第一行输入一个整数 1≤T≤10^5 为数据组数
接下来 T 行,每行输入两个整数 n,m (1≤n≤10^9,0≤m≤n)
输出格式
输出 T 行,每行一个整数做为答案
输入样例
5
3 1
3 2
3 3
4 0
5 2
输出样例
4
5
6
0
12
样例解释
第一组数据中,s=010时,f(s)=4
第二组数据中,s=101时,f(s)=5
第三组数据中,s=111时,f(s)=6
第四组数据中,s=0000时,f(s)=0
第五组数据中,s=01010时,f(s)=12
问题解析
其实我们也能感觉到,当1分开放且尽量放在中间,能得到的f(s)最大,毕竟这样每个1能提供的贡献可以最大,比如长度为6,1个数为2,001010和000011和001100得到的f(s)分别是,16、7、15。其实也可以验证,当1分开放时,每个1可以提供的长度为2的串有01和10两种,这样两个1可以提供4个,但要是两个1挨在一起,那一共就是01、11和10三种,少了一种,放在边界也是一样的。
这里1分开的 距离越远且离边界的距离越远,他们可以单独提供的f(s)就越大。这样可以提高每个1的利用率,所以我们就把每个1等距的摆放即可。然后每个1能单独提供的子串数量取决于它们距离边界或其它1的距离,比如00100100,每个1可以单独提供2个长度为2和3个长度为3的字符串,我们先算它们能单独提供的f(s)是多少。然后再算其它1合在一起的f(s),两者加一起即可。其它1合在一起的f(s)也好算,当每个每个1能提供的长度算完后,后面的字符串长度每次都会有至少一个的1在里面,那么我们就枚举字符串的长度一直到n为止就行。当然一个个算是会超时的,但我们也能看出来,这两次计算f(s)都是一种等差数列的情况,我们可以用等差数列的前n项和来算,由于第一次的f(s)是计算每个1的单独贡献,所以是1的数量乘上每个1的贡献。
AC代码
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;
const int N = 4e5 + 50;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
cin >> t;
while (t--)
{
ll n, m;
cin >> n >> m;
ll res = m;
if (m == 0)
{
cout << 0 << endl;
continue;
}
n -= m;
ll ans = n / (m + 1) + 1;
res += m * ((2 + ans) * (ans - 1) / 2);
res += (1 + n - ans + m) * (n - ans + m) / 2;
cout << res << endl;
}
return 0;
}