求递增五元组的个数
不断更新的动态规划?
记c[i][j]为前k个数(当前状态)中以j结尾的递增i元组的个数
若第k+1个数为a[k+1],则c[i][a[k+1]]+=sum(c[i-1][j]),2<=i<=5,1<=j
答案为sum(c[5][a[i]]),每次在更新第i个数之前进行叠加!
区间和加法可以用树状数组优化!
记c[i][j]为前k个数(当前状态)中树状数组意义下以j项节点区间所有点结尾的递增i元组的个数和
进行sum和update操作即可得出结果
技巧:直接记录c[5][a[k]]=sum(4,a[k]-1),省去c[5][j]层数组,节省空间
注意大整数运算!
#include
#include
#include
#include
#define maxn 50010
#define mem(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define rad 10000//大整数运算中的单位
using namespace std;
struct bint{
int v[8],l;
bint(){
v[1]=0;
l=1;
}
};
int n,s[maxn],s0[maxn],s1[maxn];
bint c[5][maxn];
/*大整数运算*/
inline void print(bint a){
printf("%d",a.v[a.l]);
for(int i=a.l-1;i;i--)
printf("%04d",a.v[i]);
printf("\n");
}
bint operator+(bint a,bint b){
if(a.l=rad)
{
if(i==a.l)
{
a.v[i+1]=0;
a.l++;
}
a.v[i+1]+=a.v[i]/rad;
t=max(t,i+1);
a.v[i]%=rad;
}
return a;
}
inline bint operator+(bint a,int p){
bint b;
b.v[1]=p;b.l=1;
return a+b;
}
void seperate(){//离散化
sort(s0+1,s0+n+1);
for(int i=1;i<=n;i++)
s1[i]=lower_bound(s0+1,s0+n+1,s[i])-s0;//映射到1...n中去
}
void update(int i,int j,bint x){
for(;j<=n;j+=lowbit(j)) c[i][j]=c[i][j]+x;
}
bint sum(int i,int j){
bint ss;
for(;j>0;j-=lowbit(j)) ss=ss+c[i][j];
return ss;
}
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
s0[i]=s[i];
}
seperate();
mem(c,0);
bint ans;
for(int j=1;j<=n;j++){
bint tmp;
tmp.v[1]=1;//tmp是1
update(1,s1[j],tmp);
ans=ans+sum(4,s1[j]-1);//因为只需要输出sum(5,n),用ans每次计数,省去一个树状数组,节省空间和时间
for(int i=2;i<5;i++){
update(i,s1[j],sum(i-1,s1[j]-1));//sum(1,s[j]-1)
}
}
print(ans);
}
}
求递增三元组的个数
简化动规解法
cc[i]:从前往后扫描,当前比第i个数小的个数
dd[i]:从后往前扫描,当前比第i个数小的个数
出现第i个数,在数轴上a[i]处做标记,询问时求区间和即可。
#include
#include
#define lowbit(x) x&(-x)
#define ll long long
using namespace std;
struct FenwickTree{
int n;
vector c;
void clear() { fill(c.begin(),c.end(),0); }
void resize(int n) { this->n=n; c.resize(n); }
//a[1]+a[2]+...+a[x]
int sum(int x){
int ret=0;
for(;x>0;x-=lowbit(x)) ret+=c[x];
return ret;
}
//a[x]+=d
void add(int x,int d) { for(;x<=n;x+=lowbit(x)) c[x]+=d; }
};
const int maxn=20000+5;
int n,a[maxn],cc[maxn],dd[maxn];
FenwickTree f;
int main(){
int T;
//freopen("a.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int maxa=0;
for(int i=1;i<=n;i++) { scanf("%d",&a[i]);maxa=max(maxa,a[i]); }
f.resize(maxa);
f.clear();
for(int i=n;i>=1;i--)
f.add(a[i],1),dd[i]=f.sum(a[i]-1);
f.clear();
for(int i=1;i<=n;i++)
f.add(a[i],1),cc[i]=f.sum(a[i]-1);
ll ans=0;
for(int i=1;i<=n;i++)
ans+=(ll)cc[i]*(n-i-dd[i])+(ll)(i-cc[i]-1)*dd[i];
printf("%lld\n",ans);
}
return 0;
}