2022-04-06每日刷题打卡
代码源——每日一题
优美!最长上升子序列 - 题目 - Daimayuan Online Judge
多组数据。
每组将给定一个数组。派派希望从中选择一个递增的子序列,越长越好。
但派派认为,这样选出来的子序列依然不够「优美」,形式化的讲,派派希望选择的下标(从 1 开始)需要满足
i1∣i2∣i3∣⋯∣ik
其中 a|b 表示整除, 即 a 是 b 的约数。
请你帮助派派完成任务吧!
注:子序列的含义不再赘述。
输入格式
第一行一个整数 T,表示接下来有 T 组数据。
每组数据包含两行,第一行包含一个整数 N。
随后一行,包含 N 个整数,表示原数组 {A}。
输出格式
对于每组数据,输出一行,包含一个数,表示能选出的「优美」的最长上升子序列长度。
数据规模
- 1≤T≤100
- 1≤N≤10^6,但保证 ∑i=1TNi≤10^6
- 1≤Ai≤10^9
样例输入
4
4
1 4 6 7
2
2 2
10
1 2 3 4 5 6 7 8 9 10
10
10 9 8 6 5 2 3 1 2 1
样例输出
3
1
4
1
解释:
对于第一组数据,能选择的「优美」最长上升子序列为 {A1,A2,A4}={1,4,7}。
对于第三组数组,选择 {A1,A2,A4,A8}={1,2,4,8}。
对于第四组数据,可选择的「优美」最长上升子序列长度为 1。
一开始有点懵,不理解是什么意思,后来发现跟一般的求最长上升子序列差不多。
这里和一般的求最长上升子序列就多了一个条件:选择的最长上升子序列,他们在数组v里的位置(从1开始,不是0)要呈倍数关系。那我从位置1开始,只看我枚举位置的倍数能不能凑成上升子序列就行。比如我枚举的位置是2,那我就看4 6 8……这些位置能不能和第二个位置凑成上升序列。我们可以准备一个dp数组,dp[i]的意思是,以v[i]为结尾的最长上升子序列的长度。我们就看,如果倍数位置j的数大于我们枚举的位置i的数,就看是当前dp[j]存的位置和dp[i]+1那个大。我们选最大的。最后输出dp数组里存储的最大值。
#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;
inline int read() {
int x = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
void write(int x) {
if (x > 9) write(x / 10);
putchar(x % 10 | '0');
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
t=read();
while (t--)
{
int n, mx = 1;
n=read();
vector<int>v(n+1), dp(n+1,1);
for (int i = 1; i <= n; i++)v[i]=read();
for (int i = 1; i <= n; i++)
{
for (int j = i * 2; j <= n; j += i)
{
if (v[j] > v[i])dp[j] = max(dp[j], dp[i] + 1);
mx = max(mx, dp[j]);
}
}
write(mx);
putchar('\n');
}
return 0;
}
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
这题我觉得要比div2还简单些。
其实我们也能感觉到,当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的贡献。
#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;
}