1561A Simply Strange Sort 题目链接:点击这里传送
题意: 现给出一串序列,要将其变成升序。关于一趟排序的定义是
for (int i = 1; i <= n-2; i += 2)
{
if (a[i] > a[i + 1]) swap(a[i], a[i + 1]);
}
或者
for (int i = 2; i <= n-1 ; i += 2)
{
if (a[i] > a[i + 1]) swap(a[i], a[i + 1]);
}
问最少要几趟。 思路: 题目咋说就咋做
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1005
int a[MAXN];
int n, t;
bool check()
{
for (int i = 1; i <= n; i++)
{
if (a[i] != i) return 0;
}
return 1;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
memset(a, 0, sizeof(a));
cin >> n;
int cnt = 0;
for (int i = 1; i <= n; i++) cin >> a[i];
while (1)
{
if (check() == 1) break;
for (int i = 1; i <= n-2; i += 2)
{
if (a[i] > a[i + 1]) swap(a[i], a[i + 1]);
}
cnt++;
if (check()==1) break;
for (int i = 2; i <= n-1 ; i += 2)
{
if (a[i] > a[i + 1]) swap(a[i], a[i + 1]);
}
cnt++;
}
cout << cnt << endl;
}
return 0;
}
1561B Charmed by the Game 题目链接:点击这里传送
题意: 给出一场乒乓球比赛的最终得分,求出所有可能的破发球情况。 思路: 第一视角解说 破发球次数=我方破发球次数+我方被破发球次数 总得分为偶数,我方发球次数=sum
÷
\div
÷ 2 总得分为奇数,我方发球次数=sum
÷
\div
÷ 2或者sum
÷
\div
÷ 2+1。 我方破发球次数=我方得分-我方成功发球次数 我方被破发球次数=我方发球次数-成功发球次数 我方得分已知,我方发球次数已知,只需枚举我方成功发球次数即可。 需要注意的是,我方得是得分少的那个,这样才能确保成功发球次数。如果用得分多的,假设他的分数超过了我方发球次数,那么就不能通过
[
0
,
我
方
得
分
]
\left[0,我方得分\right]
[0,我方得分]来枚举我方发球成功次数了。
#include<bits/stdc++.h>
using namespace std;
set <int> s;
int n, m,t;
int sum;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
s.clear();
cin >> n >> m;
sum = n + m;
if (n > m) swap(n, m);
if (sum % 2 == 0)
{
for (int i = 0; i <= n; i++) s.insert(n - i + sum / 2 - i);
}
else
{
for (int i = 0; i <= n; i++)
{
s.insert(n - i + sum / 2 - i);
s.insert(n - i + sum / 2 + 1 - i);
}
}
cout << s.size() << endl;
for (auto x : s) cout << x << " ";
cout << endl;
}
return 0;
}
1561C Deep Down Below 题目链接:点击这里传送
题意: 你是一名战士,你要去打怪升级。你有初始攻击力为n点,假设怪物有m点护甲值,只有当n>m时才能打得过怪并且获得+1攻击力,否则你就死了。现在你要去刷副本,一个副本内必须按照给定的怪物顺序一个一个杀过去。你可以任意挑选挑战副本的顺序。现在你有一个修改器,可以调整初始攻击力,问最少需要多少初始攻击力才能打通所有副本。 思路: 设一个副本内怪物的攻击力为
a
i
a_i
ai?,需要
a
1
+
1
a_{1}+1
a1?+1,
a
2
+
1
?
1
a_{2}+1-1
a2?+1?1,
a
3
+
1
?
2
a_3+1-2
a3?+1?2+……+
a
n
+
1
?
(
n
?
1
)
a_n+1-(n-1)
an?+1?(n?1)点攻击力。把这其中最高的攻击力拿出来就是通关这个副本需要的最小攻击力,设他为
b
i
b_i
bi?。 将b数组进行升序排序。进行模拟找出通关所有副本的最小初始攻击力。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int t, n,m;
#define MAXN 100005
ll a[MAXN];
struct node
{
ll val;
int num;
}b[MAXN];
bool cmp(node a, node b) { return a.val < b.val; }
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
cin >> n;
for (int k = 1; k <= n; k++)
{
cin >> m;
ll temp = 0;
for (int i = 1; i <= m; i++)
{
cin >> a[i];
a[i] = a[i] - (i - 1);
temp = max(temp, a[i]+1);
}
b[k].val = temp;
b[k].num = m;
}
sort(b + 1, b + 1 + n,cmp);
ll ans = 0;
ll num = 0;
ll current_attack = 0;
for (int i = 1; i <= n; i++)
{
if (current_attack >= b[i].val)
{
current_attack += b[i].num;
}
else
{
ans = ans + (b[i].val - current_attack);
current_attack = b[i].val+b[i].num;
}
num += b[i].num;
}
cout << ans << endl;
}
return 0;
}
1561D1 Up the Strip (simplified version) 题目链接:点击这里传送
题意: 有一个数n,你要将他变成1.你可以把他变成n/2,也可以将他变成n-1,求有多少种操作的方法能将n变为1. 思路: 设dp
[
i
]
\left[i\right]
[i]表示i变为1的方法数。初始化dp
[
1
]
\left[1\right]
[1]=1. 状态转移方程:
d
p
[
i
]
=
d
p
[
i
?
x
]
+
d
p
[
i
/
x
]
dp\left[i\right]=dp\left[i-x\right]+dp\left[i/x\right]
dp[i]=dp[i?x]+dp[i/x],枚举x直接暴力,时间复杂度肯定不够
d
p
[
i
?
x
]
dp\left[i-x\right]
dp[i?x]的和这个式子可以用前缀和表示
∑
x
=
2
i
d
p
[
i
/
x
]
=
d
p
[
i
/
2
]
+
d
p
[
i
/
3
]
+
d
p
[
i
/
4
]
+
…
…
+
d
p
[
i
/
i
]
\sum_{x=2}^i{dp\left[i/x\right]}=dp\left[i/2\right]+dp\left[i/3\right]+dp\left[i/4\right]+……+dp\left[i/i\right]
∑x=2i?dp[i/x]=dp[i/2]+dp[i/3]+dp[i/4]+……+dp[i/i]
d
p
[
i
/
2
]
+
d
p
[
i
/
3
]
+
d
p
[
i
/
4
]
+
…
…
+
d
p
[
i
/
i
]
=
d
p
[
i
/
1
]
+
d
p
[
i
/
2
]
+
d
p
[
i
/
3
]
+
d
p
[
i
/
4
]
+
…
…
+
d
p
[
i
/
i
]
?
d
p
[
i
/
1
]
dp\left[i/2\right]+dp\left[i/3\right]+dp\left[i/4\right]+……+dp\left[i/i\right]=dp\left[i/1\right]+dp\left[i/2\right]+dp\left[i/3\right]+dp\left[i/4\right]+……+dp\left[i/i\right]-dp\left[i/1\right]
dp[i/2]+dp[i/3]+dp[i/4]+……+dp[i/i]=dp[i/1]+dp[i/2]+dp[i/3]+dp[i/4]+……+dp[i/i]?dp[i/1] 这个式子可以用整除分块来做。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 200005
ll n, mod;
ll dp[MAXN];
ll sum[MAXN];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> mod;
dp[1] = 1;
sum[1] = dp[1];
for (int i = 2; i <= n; i++)
{
dp[i] = (dp[i] + sum[i - 1]) % mod;
ll substract = dp[i];
ll ans = 0;
for (int l = 1, r; l <= i; l = r + 1)
{
r = i / (i / l);
ans += ((r - l + 1) * (dp[(i / l)%mod])%mod);
}
dp[i] =(dp[i]+ ans - substract)%mod;
sum[i] = (sum[i - 1] + dp[i]) % mod;
}
cout << dp[n];
return 0;
}
D2普通的整除分块也不行,得把
O
(
s
q
r
t
n
)
O(sqrtn)
O(sqrtn)的复杂度降到
O
(
l
o
g
n
)
O(logn)
O(logn),不会。
|