cf1208 D Restore Permutation (二分+树状数组)
2024-09-03 22:54:28
题意
让你构造一个长度为n的序列,记为p1……pn,(这个序列是1~n的全排列的一种)
给你n个数,记为s1……sn,si的值为p1……pi-1中小于pi的数的和。
思路
显然,应该倒着来,也就是从pn 开始构造,这样的话,当要填pi 的时候,p1到pi-1就是所有的还未填的数,那么我们只需要去找哪个前缀和符合就可以了。
比如:现在还没填进去的数是 1,2,3,4,5
而我现在的si 是6,那么,对应的pi 就是4,因为这样无论1,2,3,5怎么排,都符合si 为6
(才学疏浅,不怎么会讲)
那么,选完要删除,所以要修改前缀和,考虑用树状数组,查找哪个符合,自然是二分。
代码
#include <stdio.h>
#include <queue>
#include <string>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <set>
using namespace std;
typedef long long int ll;
const int maxn = 2e5 + ;
const int inf = ;
const ll mod = ;
const ll seed = ;
ll s[maxn],c[maxn],ans[maxn],n;
int lowbit(int x)
{
return x & (-x);
}
void insert(ll x,int i)
{
while(i <= n){
c[i] += x;
i += lowbit(i);
}
}
ll getsum(int i)
{
ll sum = ;
while(i > ){
sum += c[i];
i -= lowbit(i);
}
return sum;
}
int vis[maxn];
int query(ll x)
{
int l,r,mid;
ll res;
l = ;r = n;
while(l <= r){
mid = (l + r) >> ;
res = getsum(mid);
if(res == x){
if(vis[mid + ])
l = mid + ;
else
return mid;
}
else if(res < x){
l = mid + ;
}
else{
r = mid - ;
}
}
}
int main()
{
while(scanf("%d",&n) != EOF){
memset(vis,,sizeof(vis));
memset(c,,sizeof(c));
for(int i = ;i <= n;i++){
scanf("%lld",&s[i]);
insert(i,i);
} for(int i = n;i >= ;i--){
ans[i] = query(s[i]) + ;
vis[ans[i]] = ;
insert(-ans[i],ans[i]);
}
for(int i = ;i <= n;i++)
printf("%d ",ans[i]);
puts("");
}
return ;
}
最新文章
- Unity插件使用总结
- php 数组动态添加实现代码(最土团购系统的价格排序)
- sublime text install packages报错
- 如何制作快速加载的HTML页面
- SPSS 统计图形
- ASP.NET MVC视图中的@Html.xxx(...)
- Oracle的 Pfile生成
- 深入理解web项目的配置文件
- 给iphone模拟器添加照片
- 再次深入理解delphi的类
- curl 返回响应头
- Bootstrap+Knockout.JS+ASP.Net MVC3+PetaPOCO实现CRUD操作
- java数据类型转换那点事
- LintCode Majority Number II / III
- [Linux]Debian 9重启DNS重置问题
- 【详细】【转】CentOS 7部署ASP.NET Core应用程序
- Ubuntu16.04下安装搭配Python3.6相关配置软件方法
- Hugepage介绍以及实践
- 关于h5屏幕适配
- node 利用http和cheerio编写简易爬虫