A. Dalton the Teacher
思路:显然我们可以在一步操作使两个sad的学生变得happy,设有s个sad的学生,那么答案显然是 。
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
int n;
cin>>n;
int res=0;
for(int i=0,t;i<n;i++){
cin>>t;
if(t==i+1)res++;
}
cout<<(res+1)/2<<'\n';
return;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
B. Longest Divisors Interval
思路:显然l从1开始可以得到最优解。
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
ll n;
cin>>n;
for(int i=1;i<=n+1;i++){
if(n%i!=0){
cout<<i-1<<'\n';
return;
}
}
return;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
C1. Dual (Easy Version)
思路:我们可以发现如果数组是全非负或者全非正的,那么我们可以在最多n-1次操作使其变为符合要求的。那么我们考虑如何使其变为全非负或者全非正的,我们可以找到数组中绝对值最大的数,如果其为正,那么数组所有数加上它就变为非负的;如果其为负,那么所有数加上它就变成非正的了。此操作最多也为n-1次,所以总操作为2*n-2次,满足题意。
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
int n;
cin>>n;
vector<int>a(n);
int t=0;
for(int i=0;i<n;i++)cin>>a[i];
for(int i=0;i<n;i++)t=max(t,abs(a[i]));
int j;
for(int i=0;i<n;i++)if(abs(a[i])==t)j=i;
vector<array<int,2>>res;
if(a[j]>0){
for(int i=0;i<n;i++){
if(a[i]<0){
res.push_back({i,j});
a[i]+=a[j];
}
}
for(int i=1;i<n;i++){
if(a[i]<a[i-1]){
res.push_back({i,j});
a[i]+=a[j];
if(a[i]>a[j])j=i;
}
}
}
else{
for(int i=0;i<n;i++){
if(a[i]>0){
res.push_back({i,j});
a[i]+=a[j];
}
}
for(int i=n-2;i>=0;i--){
if(a[i]>a[i+1]){
res.push_back({i,j});
a[i]+=a[j];
if(a[i]<a[j])j=i;
}
}
}
cout<<res.size()<<endl;
for(auto [x,y]:res)cout<<x+1<<" "<<y+1<<'\n';
return;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
C2. Dual (Hard Version)
思路:现在我们考虑如何优化使数组变为非负或者非正的操作次数,首先我们可以考虑负数和正数的数量,假设负数多,我们可以考虑都变为负,使用5次操作将一个负数倍增,使其变为一定<-20,那么操作数可能是9+5+19=33次还是不满足题意;那么我们再考虑到C1中的操作,假设绝对值最大的数为正数,设负数的数量为x,那么操作数是x+19,显然当x<13时满足;当x>=13时我们就可以用上述的第一种办法,那么操作数最大为7+5+19满足了题意。
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
int n;
cin>>n;
vector<int>a(n);
for(int i=0;i<n;i++)cin>>a[i];
int j=0;
for(int i=0;i<n;i++)if(abs(a[i])>abs(a[j]))j=i;
vector<array<int,2>>res;
bool ok=1;
if(a[j]>0){
int cnt=0;
for(int i=0;i<n;i++){
if(a[i]<0){
cnt++;
}
}
if(cnt<=12){
for(int i=0;i<n;i++){
if(a[i]<0){
res.push_back({i,j});
a[i]+=a[j];
}
}
}
else{
ok=0;
j=0;
for(int i=0;i<n;i++){
if(a[i]<a[j])j=i;
}
for(int i=0;i<5;i++){
a[j]+=a[j];
res.push_back({j,j});
}
for(int i=0;i<n;i++){
if(a[i]>0){
res.push_back({i,j});
a[i]+=a[j];
}
}
}
}
else{
int cnt=0;
for(int i=0;i<n;i++){
if(a[i]>0){
cnt++;
}
}
if(cnt<=12){
ok=0;
for(int i=0;i<n;i++){
if(a[i]>0){
res.push_back({i,j});
a[i]+=a[j];
}
}
}
else{
j=0;
for(int i=0;i<n;i++){
if(a[i]>a[j])j=i;
}
for(int i=0;i<5;i++){
a[j]+=a[j];
res.push_back({j,j});
}
for(int i=0;i<n;i++){
if(a[i]<0){
res.push_back({i,j});
a[i]+=a[j];
}
}
}
}
if(ok){
for(int i=1;i<n;i++){
if(a[i]<a[i-1]){
res.push_back({i,j});
a[i]+=a[j];
if(a[i]>a[j])j=i;
}
}
}
else{
for(int i=n-2;i>=0;i--){
if(a[i]>a[i+1]){
res.push_back({i,j});
a[i]+=a[j];
if(a[i]<a[j])j=i;
}
}
}
cout<<res.size()<<endl;
for(auto [x,y]:res)cout<<x+1<<" "<<y+1<<'\n';
return;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
D. Earn or Unlock
思路:首先我们可以得出如果我们可以刚好到达i,那么此时的答案就是前缀和s[i] - i + 1。那么我们考虑如何得到是否可以恰好到达 i 。类似于背包问题容量为 i ,时间复杂度是n*n。考虑如何优化此问题,我们可以想到使用 bitset 优化得到一个集合储存了前 i 个点可到达的点的集合。但是我们要考虑到后 n+1 ~ 2*n 也是可到达的,我们考虑进去即可。
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
int n;
cin>>n;
vector<int>a(n+1);
vector<ll>s(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
bitset<200005>b;
ll res=0;
b[1]=1;
for(int i=1;i<=n;i++){
b|=(b<<a[i]);
if(b[i]){
res=max(res,s[i]-i+1);
b[i]=0;
}
}
for(int i=n+1;i<=2*n;i++){
if(b[i])res=max(res,s[n]-i+1);
}
cout<<res<<endl;
return;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int t=1;
while(t--){
solve();
}
return 0;
}
E. Expected Destruction
思路:我们可以将题意转化为从1到 m+1 的数轴上有n个点,每个点可以向前走一格,当两个相遇时汇合成一个点,那么我们也可以看成当 x 撞到 x+1 时,x+1 这个点消失,那么对于 ai 和 ai+1 两个点来说,ai 需要走多少步撞到下一个点的期望是独立与其他点的。所以我们可以分别求解每个点所要走步数的期望,设 为从 i 走到 j 点 i 所需走的步数。那么,我们在最后再加上一个 m+1 这个点即可以得到答案。
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
template<class T>
constexpr T power(T a, ll b) {
T res = 1;
for (; b; b /= 2, a *= a) {
if (b % 2) {
res *= a;
}
}
return res;
}
constexpr ll mul(ll a, ll b, ll p) {
ll res = a * b - ll(1.L * a * b / p) * p;
res %= p;
if (res < 0) {
res += p;
}
return res;
}
template<ll P>
struct MLong {
ll x;
constexpr MLong() : x{} {}
constexpr MLong(ll x) : x{norm(x % getMod())} {}
static ll Mod;
constexpr static ll getMod() {
if (P > 0) {
return P;
} else {
return Mod;
}
}
constexpr static void setMod(ll Mod_) {
Mod = Mod_;
}
constexpr ll norm(ll x) const {
if (x < 0) {
x += getMod();
}
if (x >= getMod()) {
x -= getMod();
}
return x;
}
constexpr ll val() const {
return x;
}
explicit constexpr operator ll() const {
return x;
}
constexpr MLong operator-() const {
MLong res;
res.x = norm(getMod() - x);
return res;
}
constexpr MLong inv() const {
assert(x != 0);
return power(*this, getMod() - 2);
}
constexpr MLong &operator*=(MLong rhs) & {
x = mul(x, rhs.x, getMod());
return *this;
}
constexpr MLong &operator+=(MLong rhs) & {
x = norm(x + rhs.x);
return *this;
}
constexpr MLong &operator-=(MLong rhs) & {
x = norm(x - rhs.x);
return *this;
}
constexpr MLong &operator/=(MLong rhs) & {
return *this *= rhs.inv();
}
friend constexpr MLong operator*(MLong lhs, MLong rhs) {
MLong res = lhs;
res *= rhs;
return res;
}
friend constexpr MLong operator+(MLong lhs, MLong rhs) {
MLong res = lhs;
res += rhs;
return res;
}
friend constexpr MLong operator-(MLong lhs, MLong rhs) {
MLong res = lhs;
res -= rhs;
return res;
}
friend constexpr MLong operator/(MLong lhs, MLong rhs) {
MLong res = lhs;
res /= rhs;
return res;
}
friend constexpr std::istream &operator>>(std::istream &is, MLong &a) {
ll v;
is >> v;
a = MLong(v);
return is;
}
friend constexpr std::ostream &operator<<(std::ostream &os, const MLong &a) {
return os << a.val();
}
friend constexpr bool operator==(MLong lhs, MLong rhs) {
return lhs.val() == rhs.val();
}
friend constexpr bool operator!=(MLong lhs, MLong rhs) {
return lhs.val() != rhs.val();
}
};
template<>
ll MLong<0LL>::Mod = ll(1E18) + 9;
template<int P>
struct MInt {
int x;
constexpr MInt() : x{} {}
constexpr MInt(ll x) : x{norm(x % getMod())} {}
static int Mod;
constexpr static int getMod() {
if (P > 0) {
return P;
} else {
return Mod;
}
}
constexpr static void setMod(int Mod_) {
Mod = Mod_;
}
constexpr int norm(int x) const {
if (x < 0) {
x += getMod();
}
if (x >= getMod()) {
x -= getMod();
}
return x;
}
constexpr int val() const {
return x;
}
explicit constexpr operator int() const {
return x;
}
constexpr MInt operator-() const {
MInt res;
res.x = norm(getMod() - x);
return res;
}
constexpr MInt inv() const {
assert(x != 0);
return power(*this, getMod() - 2);
}
constexpr MInt &operator*=(MInt rhs) & {
x = 1LL * x * rhs.x % getMod();
return *this;
}
constexpr MInt &operator+=(MInt rhs) & {
x = norm(x + rhs.x);
return *this;
}
constexpr MInt &operator-=(MInt rhs) & {
x = norm(x - rhs.x);
return *this;
}
constexpr MInt &operator/=(MInt rhs) & {
return *this *= rhs.inv();
}
friend constexpr MInt operator*(MInt lhs, MInt rhs) {
MInt res = lhs;
res *= rhs;
return res;
}
friend constexpr MInt operator+(MInt lhs, MInt rhs) {
MInt res = lhs;
res += rhs;
return res;
}
friend constexpr MInt operator-(MInt lhs, MInt rhs) {
MInt res = lhs;
res -= rhs;
return res;
}
friend constexpr MInt operator/(MInt lhs, MInt rhs) {
MInt res = lhs;
res /= rhs;
return res;
}
friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {
ll v;
is >> v;
a = MInt(v);
return is;
}
friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {
return os << a.val();
}
friend constexpr bool operator==(MInt lhs, MInt rhs) {
return lhs.val() == rhs.val();
}
friend constexpr bool operator!=(MInt lhs, MInt rhs) {
return lhs.val() != rhs.val();
}
};
template<>
int MInt<0>::Mod = 998244353;
template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();
constexpr int P = 1000000007;
using Z = MInt<P>;
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int n,m;
cin>>n>>m;
vector<int>a(n+1);
for(int i=0;i<n;i++)cin>>a[i];
a[n]=m+1;
vector<vector<Z>>dp(m+1,vector<Z>(m+1,0));
for(int i=m-1;i>=0;i--){
for(int j=m;j>=i;j--){
if(i==j){
dp[i][j]=0;
}
else{
if(j==m){
dp[i][j]=dp[i+1][j]+1;
}
else dp[i][j]=CInv<2,P>*(dp[i+1][j]+1+dp[i][j+1]);
}
}
}
Z res=0;
for(int i=1;i<=n;i++){
res+=dp[a[i-1]-1][a[i]-1];
}
cout<<res<<endl;
return 0;
}