题意简述
定义一个数组的d值为这个数组中|所有数-下标|(两个竖线表示取绝对值,别看差了)的和。比如2 1 3 4的d值就是|2-1|+|1-2|+|3-3|+|4-4|=2。给定一个数组长度为n(n<=1e6),保证这个数组中有1~n的所有数字。请计算出:滚动(滚动一次a b c d变成b c d a)这个数组多少次使得d最小,一次输出滚动的次数和这个最小的d。
(这叫简述???总比嘤文题面好的多吧。。。)
数据
输入:
3
1 2 3
输出:
0 0
输入:
3
2 3 1
输出
0 1
输入:
3
3 2 1
输出:
2 1
思路
想想暴力的做法:不断滚动并求出d值,更新答案,O(n2)=O(TLE)O(n^2)=O(TLE)O(n2)=O(TLE)。
按照老套路:如何优化这个暴力使得时间复杂度是O(AC)O(AC)O(AC)?
Imagine this:如果我们只要求第一次的d值,然后每次O(1)O(1)O(1)或者O(logn)O(logn)O(logn)转移,那不就O(AC)O(AC)O(AC)了么!
但是它的转移好像毫无规律。。。等等,是毫无规律么?仔细想想,如果我们现在有lll个a[i]a[i]a[i]满足a[i]>ia[i]>ia[i]>i(除了最后一个,最后一个特判),那么整体滚动后每个∣a[i]−i∣|a[i]-i|∣a[i]−i∣将会−1-1−1(原因是正的更小了,绝对值也更小了),则总共加起来就是−l-l−l。当然,那些a[i]<=ia[i]<=ia[i]<=i的(记为rrr个)每个将会使ddd增加111(负的更多,绝对值增加),总共加起来就是+r+r+r。当然,我们珂以直接计算得r=n−l−1r=n-l-1r=n−l−1,即n−ln-ln−l再去掉最后一个元素。代码中没有写出rrr,用n−l−1n-l-1n−l−1代替了。
这样,转移d就是O(1)O(1)O(1)。设最后一个是xxx,则d=d−l+(n−l−1)+∣x−1∣−∣x−n∣d=d-l+(n-l-1)+|x-1|-|x-n|d=d−l+(n−l−1)+∣x−1∣−∣x−n∣。
那么,如何更新lll的值呢?
设一个ppp数组,p[i]p[i]p[i]表示原数组在移动了i次之后又多少个a[i]=ia[i]=ia[i]=i,则每次滚动后,lll要减去p[i]p[i]p[i]。特判最后一个(它太特殊了),还是记为xxx(跟上面的xxx是同一个),如果x!=1x!=1x!=1(在本题中这等价于x>1x>1x>1),则lll应该+1(因为xxx移到了111的位置)。注意,ppp数组也要更新,因为在这个xxx回到了开头又重新右移的时候也可能会出现x=x的下标x=x\text{的下标}x=x的下标的情况出现。为了考虑到循环,使用取模运算。(即p[(x−1+i)%n]++p[(x-1+i)\%n]++p[(x−1+i)%n]++)。
然后更新答案即可(这个可别忘了!)。最后输出最小的d和滚动多少次。
代码:
#include<bits/stdc++.h>
#define N 1001000
#define int long long
using namespace std;
int n,a[N],p[N];
void Input()
{
scanf("%I64d",&n);
for(int i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
}
}
void Solve()
{
int l=0,d=0;
for(int i=1;i<=n;i++)
{
if (a[i]>i)
{
l++,p[a[i]-i]++;
}
d+=abs(a[i]-i);
}
int ansd=d,ansi=0;
for(int i=1;i<n;i++)
{
//开始转移
int x=a[n-i+1];//取当前最后一个(不改变原数组)
d-=l;
d+=(n-l-1);
d+=abs(x-1);
d-=abs(x-n);//为了清楚,分开写
l-=p[i];
if (x!=1)
{
l++;
p[(x-1+i)%n]++;
}
if (d<ansd)//更新答案
{
ansd=d;
ansi=i;
}
}
//解释了好多,代码却很短
//"也不过如此啊!"你珂能会想
//这就是思维题的难处
//实际上这题思维量非常大
//我看着题解看着代码在学校里面用了几天才真正理解了这个题。。。
printf("%lld %lld\n",ansd,ansi);
}
main()
{
Input();
Solve();
return 0;
}
本文介绍了一种针对数组操作的算法优化技巧,通过分析数组滚动过程中的D值变化规律,实现了从O(n^2)到O(n)的时间复杂度优化。文章详细解释了如何通过维护特定计数和巧妙的状态转移实现高效求解。
9803

被折叠的 条评论
为什么被折叠?



