Codeforces Round #642 (Div. 3) 参与排名人数11823
[codeforces 1353D] Constructing the Array 分治算法
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址http://codeforces.com/contest/1353/problem/D
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
D - Constructing the Array | GNU C++17 | Accepted | 77 ms | 7500 KB |
本场比赛最大收获,在比赛中悟出了分治算法(这个是弱项),并且AC掉该题。那种感觉真奇妙。
思路:
通过分治算法,找出所有可放数据的区间,将区间按区间长度,自大到小排序,若区间长度相同,按左边界自小到大排序。
之后,将放置的数据,按顺序放入安置区间对应的安置位置。
样例分析如下
n=6
(1,6)中的3位置可放置数据
(1,6)剩下的可放置数据的区间是(1,2),(4,6)
(1,2)中的1位置可放置数据
(4,6)中的5位置可放置数据
(1,2)剩下的可放置数据的区间是(2,2)
(2,2)中的2位置可放置数据
(4,6)剩下的可放置数据的区间是(4,4),(6,6)
(4,4)中的2位置可放置数据
(6,6)中的6位置可放置数据
可放置数据的区间如下
(1,6),a[3]=1
(4,6),a[5]=2
(1,2),a[1]=3
(2,2),a[2]=4
(4,4),a[4]=5
(6,6),a[6]=6
AC代码如下
#include
#include
using namespace std;
int a[200010],cnt,tot;
struct node{
int left,right,mid,delta;//left记录区间左边界,right记录区间右边界,mid记录区间放置数据位置,delta记录区间长度
}b[200010];
int cmp(node a,node b){
return a.delta==b.delta?a.leftb.delta;//将区间按区间长度,自大到小排序,若区间长度相同,按左边界自小到大排序。
}
void dfs(int left,int right){
int mid;
if(left>right)return;//结束条件
tot++,b[tot].left=left,b[tot].right=right,b[tot].mid=(left+right)/2,b[tot].delta=right-left+1,mid=(left+right)/2;//记录安置区间的数据
dfs(left,mid-1),dfs(mid+1,right);//区间分裂,请注意,mid位置已被占用,故mid-1,mid+1
}
int main(){
int t,n,i;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=1;i<=n;i++)a[i]=0;//初始化
for(i=1;i<=n;i++)b[i].left=b[i].right=b[i].delta=0;//初始化
cnt=0,tot=0;//初始化,tot记录安置区间的数量
dfs(1,n);//找出安置数据的区间
sort(b+1,b+1+tot,cmp);//将区间按区间长度,自大到小排序,若区间长度相同,按左边界自小到大排序。
for(i=1;i<=tot;i++)a[b[i].mid]=++cnt;//cnt是指需要放置的数据
for(i=1;i<=n;i++)printf("%d ",a[i]);
printf("\n");
}
return 0;
}