241. 楼兰图腾
传送门
题目分析
'v’图腾求法
- 倒序扫描序列 a a a,利用树状数组求出每个 a [ i ] a[i] a[i]后面有几个数比它大,记录为 r i g h t [ i ] right[i] right[i]
- 正序扫描序列 a a a,利用树状数组求出每个 a [ i ] a[i] a[i]前面有几个数比它大,记录为 l e f t [ i ] left[i] left[i]
- 依次枚举每一个点为中间点,那么这个点为中心的’v’图腾的个数就是 ∑ i = 1 N l e f t [ i ] × r i g h t [ i ] \sum_{i=1}^{N}left[i]×right[i] ∑i=1Nleft[i]×right[i]
同理’^'图腾求法
- 倒序扫描序列 a a a,利用树状数组求出每个 a [ i ] a[i] a[i]后面有几个数比它小,记录为 r i g h t [ i ] right[i] right[i]
- 正序扫描序列 a a a,利用树状数组求出每个 a [ i ] a[i] a[i]前面有几个数比它小,记录为 l e f t [ i ] left[i] left[i]
- 依次枚举每一个点为中间点,那么这个点为中心的’^’图腾的个数就是. ∑ i = 1 N l e f t [ i ] × r i g h t [ i ] \sum_{i=1}^{N}left[i]×right[i] ∑i=1Nleft[i]×right[i]
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define ll long long
using namespace std;
inline int yread()
{
int x = 0, f = 1; char c = getchar();
while (c > '9' || c < '0') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
return f * x;
}
const int SIZE = 200050;
int maxn,n,m,a[SIZE];
ll ans,c[SIZE],rt[SIZE],lf[SIZE];
inline void add(int x, int val)
{
for (; x <= n; x += x & -x) c[x] += val;
}
inline ll yask(int x)
{
ll ans = 0;
for (; x; x -= x & -x) ans += c[x];
return ans;
}
inline void f1()
{
for (int i = n; i >= 1; --i)
{
rt[i] =yask(maxn) - yask(a[i]);
add(a[i], 1);
}
memset(c,0,sizeof(c));
for (int i = 1; i <= n; ++i)
{
lf[i] =yask(maxn) - yask(a[i]);
add(a[i], 1);
}
for(ll i = 1; i <= n; i++)
{
ans += lf[i] * rt[i];
}
}
inline void f2()
{
memset(c,0,sizeof(c));
for (int i = n; i >= 1; --i)
{
rt[i] = yask(a[i] - 1);
add(a[i], 1);
}
memset(c,0,sizeof(c));
for (int i = 1; i <= n; ++i)
{
lf[i] = yask(a[i] - 1);
add(a[i], 1);
}
ans = 0;
for(ll i = 1; i <= n; i++)
{
ans += lf[i] * rt[i];
}
}
int main()
{
n = yread();
for (int i = 1; i <= n; ++i)
{
a[i] = yread();
maxn = max(maxn, a[i]);
}
f1(); printf("%lld ", ans);
f2(); printf("%lld\n", ans);
return 0;
}
244. 谜一样的牛
传送门
算法分析
——摘自AcWing 244. 谜一样的牛 by秦淮岸灯火阑珊
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
inline int yread()
{
int x = 0, f = 1; char c = getchar();
while (c > '9' || c < '0') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
return f * x;
}
const int SIZE = 100050;
int n,a[SIZE],c[SIZE],ans[SIZE];
inline void add(int x, int val)
{
for (; x <= n; x += x & -x) c[x] += val;
}
inline ll yask(int x)
{
ll ans = 0;
for (; x; x -= x & -x) ans += c[x];
return ans;
}
int main()
{
n = yread(); add(1, 1);
for (int i = 2; i <= n; ++i)
{
a[i] = yread();
add(i, 1);
}
for (int i = n; i >= 1; --i)
{
int l = 1, r = n;
while (l < r)
{
int mid = l + r >> 1;
if (yask(mid) < a[i] + 1)
l = mid + 1;
else r = mid;
}
ans[i] = r;
add(r, -1);
}
for (int i = 1; i <= n; ++i)
printf("%d\n",ans[i]);
return 0;
}
总结与反思
- 注意初始化
- 要掌握灵活运用数据结构的方法