A. Cubes Sorting
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int main()
{
int t, n;
cin>>t;
while(t--)
{
cin>>n;
int cnt=0;
for (register int lst=2147483647, a, i = 1; i <= n; ++i)
{
cin>>a;
if (a<lst) ++cnt;
lst=a;
}
if (cnt==n) printf("NO\n");
else printf("YES\n");
}
return 0;
}
B. Rock and Lever
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 100005;
bool Bit[MAXN][40];
int BitTOT[MAXN];
long long Cnt[40];
long long Calc(long long x)
{
return (1ll*x*(x-1))>>1;
}
int main()
{
ios::sync_with_stdio(false);
int t, n, ones=0, zeroes=0;
cin >> t;
while (t--)
{
for (int i = 0; i < 40; ++i) Cnt[i]=0;
cin >> n;
ones=0, zeroes=0;
for (register int a, i = 1; i <= n; ++i)
{
cin >> a;
BitTOT[i]=0;
while (a)
{
Bit[i][++BitTOT[i]] = a&1;
a>>=1;
}
++Cnt[BitTOT[i]];
}
long long Ans = 0;
for (int i = 0; i < 40; ++i) Ans += Calc(Cnt[i]);
cout<<Ans<<endl;
}
return 0;
}
C1. Pokémon Army (easy version)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 3e5 + 10;
int t, n, q;
int a[MAXN];
long long Dp[2];
int main()
{
cin >> t;
while (t--)
{
cin >> n >> q;
Dp[0]=0, Dp[1]=0; long long Tmp0=0, Tmp1=0;
for (register int i = 1; i <= n; ++i)
{
cin >> a[i];
Tmp0 = max(Dp[0], Dp[1]-a[i]);
Tmp1 = max(Dp[1], Dp[0]+a[i]);
Dp[1] = Tmp1, Dp[0] = Tmp0;
}
cout << max(Dp[1], Dp[0]) << endl;
}
return 0;
}
C2. Pokémon Army (hard version)
一种方法是用线段树维护。复杂度带个 log \log log 。
当然也有
O
(
n
)
O(n)
O(n) 做法:
从例子入手。
比如说:1 3 5 7 9 5 2 4 6 8 10
显然会选择 +9 -2 +10
也就是选择了最长单调不递减序列的末尾和最长单调递减序列的末尾
差分
那么对于上面的例子,差分后答案是 1 + (9 - 1) + (10 - 2)
把差分数组里面所有正数加起来,再加上
a
1
a_1
a1 即可。
交换只需稍作讨论。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
#define DifUpdate(pos) (dif[pos] = a[pos] - a[pos-1])
#define Recall(pos) if(dif[pos] > 0) Ans -= dif[pos]
#define Calc(pos) if (dif[pos] > 0) Ans += dif[pos]
const int MAXN = 3e5 + 10;
int t, n, q;
int a[MAXN];
int dif[MAXN];
long long Ans = 0;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
cin >> n >> q;
Ans = 0;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
DifUpdate(i);
Calc(i);
}
cout << Ans << endl;
dif[0] = 0, dif[n+1] = 0;
a[0] = 0, a[n+1] = 0;
for (int qL, qR, i = 1; i <= q; ++i)
{
cin >> qL >> qR;
swap(a[qL], a[qR]);
if (qL == qR - 1)
{
Recall(qL);
Recall(qR);
Recall(qR+1);
DifUpdate(qL);
DifUpdate(qR);
DifUpdate(qR+1);
Calc(qL);
Calc(qR);
Calc(qR+1);
}
else
{
Recall(qL);
Recall(qR);
Recall(qL+1);
Recall(qR+1);
DifUpdate(qL);
DifUpdate(qR);
DifUpdate(qL + 1);
DifUpdate(qR + 1);
Calc(qL);
Calc(qR);
Calc(qL+1);
Calc(qR+1);
}
cout << Ans << endl;
}
}
return 0;
}
D. Rescue Nibel!
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 3e5+10;
int n, k, l[MAXN], r[MAXN], a[MAXN<<1];
int Mrk[MAXN<<1], MrkSub[MAXN<<1];
long long Ans = 0;
long long Fact[MAXN];
long long InvFact[MAXN];
const long long MOD = 998244353;
long long qpow(long long a, long long b)
{
long long Ans = 1;
while (b)
{
if (b & 1)
{
Ans = Ans * a % MOD;
}
a = a * a % MOD;
b >>= 1;
}
return Ans;
}
long long inv(long long a)
{
return qpow(a, MOD - 2);
}
void GetFact(int n)
{
Fact[0]=1;
for (int i = 1; i <= n; ++i)
{
Fact[i] = Fact[i-1] * i % MOD;
}
}
long long Calc(int n, int m)
{
if (n < m) return 0;
return Fact[n] * (InvFact[m] * InvFact[n-m] % MOD) % MOD;
}
void GetInvFact(int n)
{
// for (int i = 0; i <= n; ++i) InvFact[i] = inv(Fact[i]);
InvFact[n] = inv(Fact[n]);
for (int i = n-1; i >= 0; --i) InvFact[i] = InvFact[i+1] * (i+1) % MOD;
}
int main()
{
// freopen("data.in","r",stdin);
cin >> n >> k;
GetFact(n);
GetInvFact(n);
for (int i = 1; i <= n; ++i)
{
cin >> l[i] >> r[i]; ++r[i];
a[++a[0]]=l[i], a[++a[0]]=r[i];
}
sort(a + 1, a + 1 + a[0]);
a[0] = unique(a + 1, a + a[0] + 1) - a - 1;
for (int i = 1; i <= n; ++i)
{
l[i]=lower_bound(a + 1, a + 1 + a[0], l[i]) - a;
r[i]=lower_bound(a + 1, a + 1 + a[0], r[i]) - a;
++Mrk[l[i]], ++MrkSub[r[i]];
}
for (int tot = 0, i = 1; i <= a[0]; ++i)
{
tot -= MrkSub[i];
NOT!!! if (tot + Mrk[i] >= k)
// {
Ans = (Ans + MOD - Calc(tot, k)) % MOD;
// }
tot += Mrk[i];
// if (tot >= k)
// {
Ans = (Ans + Calc(tot, k)) % MOD;
// }
}
cout << Ans;
return 0;
}
E. Battle Lemmings
其实就是暴力……只要想到 DP 就可以做了
从左到右依次确定每段连续的 0
的右端 1
的最后位置。同时转移时间和答案。
剪一下枝过。
挪 1
的时候可以用前面 0
的个数代替距离,正确性显然。
注意边界。
要在 DP 的时候算出结果的话,最后应该推上最后那一段 0
并且保证枚举在末端结束
保证枚举在末端结束:首先要让枚举都能够跑到末端。
然后只需要最后输出答案的时候只考虑
ℓ
\ell
ℓ 等于原序列 0
的总数的 DP 状态即可。
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 100;
const int MAN = 4000;
int n, m = 0, N, Ze = 0, cnt = 0;
bool a;
int z[MAXN] = {};
int PreZe[MAXN] = {};
int DP[MAN][MAXN][MAXN] = {};
void Update(int& a, int b)
{
if (a==-1)
{
a = b; return;
}
if (b<a) a=b;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n;
N = n * (n - 1) >> 1;
for (int i = 1; i <= n; ++i)
{
cin >> a;
if(a) {
z[++m] = cnt;
Ze += cnt;
PreZe[m] = Ze;
cnt = 0;
}
else ++cnt;
}
// if (cnt)
// {
z[++m] = cnt;
Ze += cnt;
PreZe[m] = Ze;
// }
memset(DP, -1, sizeof(DP));
DP[0][0][0] = 0;
int ThisPara;
for (int k = 0; k <= N; ++k) // time
{
for (int j = 0; j < m; ++j) // Para M
{
for (int l = 0; l <= Ze; ++l) // Zeros
{
if (DP[k][j][l]==-1) continue;
for (int SZ = l, Walk; SZ <= Ze; ++SZ) // Zeroes To
{
Walk = k + abs(SZ - PreZe[j+1]); // Time To
if (Walk > N) continue; // Cut
ThisPara = SZ - l;
Update(DP[Walk][j+1][SZ], DP[k][j][l] + ThisPara * ThisPara);
}
}
}
}
int Ans = 0x3f3f3f3f;
int ZeZe = Ze * Ze;
for (int i = 0; i <= N; ++i)
{
if (DP[i][m][Ze] != -1 && DP[i][m][Ze] < Ans) Ans = DP[i][m][Ze];
cout << ((ZeZe - Ans) >> 1) << ' ';
}
return 0;
}