A. TubeTube Feed
题意:你有时间
t
t
t来看一个视频,跳过一个视频需要1时间,求最大乐趣的视频引索,相同取小的引索。
思路:从前往后枚举,每枚举一个视频,
t
t
t就减1
#include<bits/stdc++.h>
using namespace std;
int a[101],b[101];
int main()
{
int q;cin >> q;
while(q--){
int n,t;cin >> n >> t;
int ans = -1;
for(int i = 1;i <= n;i++){
cin >> a[i];
a[i] += i - 1;
}
for(int i = 1;i <= n;i++){
cin >> b[i];
if(a[i] <= t){
if(ans == -1 || b[ans] < b[i])
ans = i;
}
}
cout << ans << endl;
}
}
B. Karina and Array
题意:求最大相邻乘积,并且可以任意删去原数组的数
思路:排序,最大的两个相乘,最小的两个相乘,比较大小
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 2e5 + 10;
ll a[MAXN];
int main()
{
int t;cin >> t;
while(t--){
int n;cin >> n;
for(int i = 1;i <= n;i++)
cin >> a[i];
sort(a + 1,a + 1 + n);
cout << max(a[1]*a[2],a[n]*a[n - 1]) << endl;
}
}
C. Bun Lover
题意:两个卷求总边长
思路:观察得出规律
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
int t;cin >> t;
while(t--){
ll n;cin >> n;
cout << n*n + 2*n + 2 << endl;
}
}
D. Super-Permutation
题意:一个数n,要求构造数组a使得a为一个排列并且b也为一个排列,其中
b
i
=
(
(
a
1
+
a
2
+
.
.
.
+
a
i
)
m
o
d
n
)
+
1
b_i=((a_1+a_2+...+a_i)\ mod\ n)+1
bi=((a1+a2+...+ai) mod n)+1
思路:简单分析一下可得出以下结论
- 第一个数必须为n
- 如果其中一段a的和为n或n的整数倍,那么前后b的数一定相同,因此不成立
- 奇数n(1除外)情况下
[
1
,
n
−
1
]
[1,n-1]
[1,n−1]的和为n的倍数,因此必定不成立
因此现在就要构造偶数情况下的排列
- 首先第一个数为n,对应的b为1,要在
[
1
,
n
]
[1,n]
[1,n]的最左边,为了将所有数都覆盖到,我们下一次要跳到
n
n
n,因此我们输出n-1
- 现在为
n
n
n,再跳到左边,因为1已经取过,所以这次取2,即n-n+2
- 重复跳左跳右
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 2e5 + 10;
int a[MAXN];
int main()
{
int t;cin >> t;
while(t--){
int n;cin >> n;
if(n == 1){
cout << 1 << endl;
}else if(n % 2 == 1)
cout << -1 << endl;
else{
cout << n << ' ';
int now = 1;
int l = 2,r = n;
while(l <= r){
cout << r - now << ' ';
now = r;
r--;
if(now == l)
break;
cout << l + n - now << ' ';
now = l;
l++;
}
cout << endl;
}
}
}
E. Making Anti-Palindromes
题意:字符串由小写字母组成,可以交换字符串中的任意两个位置的字母,要让字符串满足对于任意的i,
s
t
r
[
i
]
!
=
s
t
r
[
n
−
i
+
1
]
str[i]!=str[n-i+1]
str[i]!=str[n−i+1],求最小的操作次数
思路:如果同一字母的数量超过半数,那么无论怎么换,必定有左右相同的那个字母的位置
如果长度为奇数,中间的字母一定与自己相同
一次交换可以减少一个重合位置,也可以减少两个,我们要让减少两个的尽量多
不同字母左右相同可以实现一次减少两个,但是如果单个字母左右相同比其他字母相同的总和都多,那么多余部分只能一个一个减少了
#include<bits/stdc++.h>
using namespace std;
int num[26],nnum[26];
int main()
{
int t;cin >> t;
while(t--){
int n;cin >> n;
memset(num,0,sizeof(num));
memset(nnum,0,sizeof(nnum));
string str;cin >> str;
if(n % 2 == 1)
cout << -1 << endl;
else{
bool f = 1;
int ans = 0;
for(int i = 0;i < n;i++){
num[str[i] - 'a']++;
if(str[i] == str[n - i - 1]){
nnum[str[i] - 'a']++;
}
}
for(int i = 0;i < 26;i++){
if(num[i] > n / 2)
f = 0;
num[i] = 0;
nnum[i] /= 2;
}
sort(nnum,nnum + 26);
if(f){
int ma = nnum[25];
nnum[25] = 0;
int left = 0;
for(int i = 0;i < 25;i++){
left += nnum[i];
nnum[i] = 0;
}
if(left >= ma){
cout << (ma + left) / 2 + ((ma + left) % 2) << endl;
}else
cout << ma << endl;
}else
cout << -1 << endl;
}
}
}
F. Gardening Friends
题意:一棵树,根一开始为1,你可以用c的费用移动根到相邻节点,利润为最远到根节点的距离减去移动节点的费用,求最大利润
思路:最远一定是直径的两个端点,因此从两个端点bfs得到每个节点的最远距离,还要从节点1bfs找每个点到原节点的距离,再遍历所有节点假设为移动后的根节点取最大值即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 2e5 + 10;
vector<int> ed[MAXN];
ll dis[2][MAXN];//记录关于1、最远端点的距离
bool use[MAXN];
int n,k,c;
ll len = 0;
int en = 0;
void bfs(int u,int op){
for(int i = 1;i <= n;i++)
use[i] = 0;
queue<int> qu;
qu.push(u);
use[u] = 1;
len = -1;
while(!qu.empty()){
int num = qu.size();
while(num--){
u = qu.front();
dis[op][u] = max(len + 1,dis[op][u]);
qu.pop();
use[u] = 1;
for(int v:ed[u]){
if(use[v])
continue;
use[v] = 1;
qu.push(v);
}
}
len++;
}
en = u;
}
int main()
{
int t;cin >> t;
while(t--){
cin >> n >> k >> c;
for(int i = 1;i <= n - 1;i++){
int u,v;cin >> u >> v;
ed[u].push_back(v);
ed[v].push_back(u);
}
bfs(1,0);
if(c >= k)//别动
{
cout << len*k << endl;
for(int i = 1;i <= n;i++){
ed[i].clear();
dis[0][i] = dis[1][i] = 0;
}
}
else{
int len1 = len;
bfs(en,1);
int len2 = len;
bfs(en,1);
ll ma = 0;
for(int i = 1;i <= n;i++){
ma = max(ma,dis[1][i]*k - dis[0][i]*c);
ed[i].clear();
dis[0][i] = dis[1][i] = 0;
}
cout << ma << endl;
}
}
}
G1. Magic Triples (Easy Version)
题意:求三元组的数量
(
i
,
j
,
k
)
(i,j,k)
(i,j,k),其中
a
[
i
]
=
b
∗
a
[
j
]
,
a
[
j
]
=
b
∗
a
[
k
]
a[i]=b*a[j],a[j]=b*a[k]
a[i]=b∗a[j],a[j]=b∗a[k]
思路:对于较小的数据范围,我们可以用桶来存,用set去重,枚举set,枚举b从1~1000,当b为1时如果数量大于3就取
A
n
3
A_n^3
An3,当b不为1时,就取num[x]*num[x*j]*num[x*j*j],再用最大值限制一下循环即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 2e5 + 10,MAXM= 1e6 + 10;
ll num[MAXM];
ll a[MAXN];
int main()
{
int t;cin >> t;
while(t--){
int n;cin >> n;
set<int> se;
ll ma = 0;
for(int i = 1;i <= n;i++){
cin >> a[i];
ma = max(ma,a[i]);
num[a[i]]++;
se.insert(a[i]);
}
ll ans = 0;
while(!se.empty()){
int x = *(se.begin());
se.erase(se.begin());
if(num[x] >= 3)
ans += num[x]*(num[x] - 1)*(num[x] - 2);
for(int j = 2;x*j*j <= ma;j++)
ans += num[x]*num[x*j]*num[x*j*j];
num[x] = 0;
}
cout << ans << endl;
}
}