AtCoder Regular Contest 077E: guruguru 题解
2017-07-02 20:39
477 查看
记favourite level=x
我们可以发现,假设a[i]<a[i+1],那么如果x取a[i]+1~a[i+1]之间的值,那么可以省下的步数满足关系式f(x)=x-a[i]-1
于是我们可以用线段树在这个区间上打一个公差为一的递增标记,最后对1~m的每个点做单点查询,看哪个能省下最多的步数
但是这个做法还是慢了一些,是O(nlogn)的,我们不妨思考有没有更快的做法
事实上,满足一次函数关系式的区间修改有一种更好的修改方法:单独维护k和b,这样在这个区间中我们只要在斜率(k)标记上+1,在b标记上减去a[i]+1即可
对一个区间统一加上一个值有更快的做法,即差分数组
差分数组相当于一个前缀和数组,维
4000
护的是后一项比前一项多多少,所以我们可以发现一个区间+1,区间内的相邻的数的差是不变的,所以只要在区间头+1,区间尾-1即可
于是这样可以做到O(n)
我们可以发现,假设a[i]<a[i+1],那么如果x取a[i]+1~a[i+1]之间的值,那么可以省下的步数满足关系式f(x)=x-a[i]-1
于是我们可以用线段树在这个区间上打一个公差为一的递增标记,最后对1~m的每个点做单点查询,看哪个能省下最多的步数
#include <cstdio> #include <iostream> #include <cstring> #include <string> #include <cmath> #include <algorithm> #include <cstdlib> #include <utility> #include <map> #include <stack> #include <set> #include <vector> #include <queue> #include <deque> #define x first #define y second #define mp make_pair #define pb push_back #define LL long long #define Pair pair<int,int> #define LOWBIT(x) x & (-x) using namespace std; const int MOD=1e9+7; const int INF=0x7ffffff; const int magic=348; struct node { int left,right; LL tag; int cnt; }tree[300048]; void build(int cur,int left,int right) { tree[cur].left=left;tree[cur].right=right; tree[cur].tag=tree[cur].cnt=0; if (left!=right) { int mid=(left+right)>>1; build(cur*2,left,mid); build(cur*2+1,mid+1,right); } } void update(int cur,int left,int right,int st) { if (left<=tree[cur].left && tree[cur].right<=right) { tree[cur].tag+=st+tree[cur].left-left; tree[cur].cnt++; return; } int mid=(tree[cur].left+tree[cur].right)>>1; if (left<=mid) update(cur*2,left,right,st); if (mid+1<=right) update(cur*2+1,left,right,st); } LL query(int cur,int pos) { if (tree[cur].left==tree[cur].right) { return tree[cur].tag; } int mid=(tree[cur].left+tree[cur].right)>>1;LL res; if (pos<=mid) res=query(cur*2,pos); else res=query(cur*2+1,pos); res+=(pos-tree[cur].left)*tree[cur].cnt+tree[cur].tag; return res; } int n,m; int a[100048]; int main () { int i; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,m); for (i=1;i<=n-1;i++) { if (a[i]<a[i+1] && a[i+1]-a[i]>=2) update(1,a[i]+2,a[i+1],1); if (a[i]>a[i+1]) { if (a[i]+2<=m) update(1,a[i]+2,m,1); if (m-a[i]>=1) update(1,1,a[i+1],m-a[i]); else if (a[i+1]>=2) update(1,2,a[i+1],1); } } LL ans=0,res,ans_res=-1; for (i=1;i<=n-1;i++) if (a[i]<a[i+1]) ans+=a[i+1]-a[i]; else ans+=m-(a[i]-a[i+1]); for (i=1;i<=m;i++) { res=query(1,i); if (res>ans_res) ans_res=res; } cout<<ans-ans_res<<endl; return 0; }
但是这个做法还是慢了一些,是O(nlogn)的,我们不妨思考有没有更快的做法
事实上,满足一次函数关系式的区间修改有一种更好的修改方法:单独维护k和b,这样在这个区间中我们只要在斜率(k)标记上+1,在b标记上减去a[i]+1即可
对一个区间统一加上一个值有更快的做法,即差分数组
差分数组相当于一个前缀和数组,维
4000
护的是后一项比前一项多多少,所以我们可以发现一个区间+1,区间内的相邻的数的差是不变的,所以只要在区间头+1,区间尾-1即可
于是这样可以做到O(n)
#include <cstdio> #include <iostream> #include <cstring> #include <string> #include <cmath> #include <algorithm> #include <cstdlib> #include <utility> #include <map> #include <stack> #include <set> #include <vector> #include <queue> #include <deque> #define x first #define y second #define mp make_pair #define pb push_back #define LL long long #define Pair pair<int,int> #define LOWBIT(x) x & (-x) using namespace std; const int MOD=1e9+7; const int INF=0x7ffffff; const int magic=348; int n,m; int a[200048]; LL s1[200048],s2[200048]; int main () { int i; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) scanf("%d",&a[i]); int from,to; for (i=1;i<=n-1;i++) { from=a[i];to=a[i+1]; if (from>to) to+=m; s1[from+1]+=from+1;s1[to+1]-=(from+1); s2[from+1]++;s2[to+1]--; } for (i=2;i<=m*2;i++) { s1[i]+=s1[i-1]; s2[i]+=s2[i-1]; } LL ans=0,res,fans=1e16; for (i=1;i<=n-1;i++) if (a[i]<a[i+1]) ans+=a[i+1]-a[i]; else ans+=m-(a[i]-a[i+1]); for (i=1;i<=m;i++) { res=s2[i]*i+s2[i+m]*(i+m)-s1[i]-s1[i+m]; if (ans-res<fans) fans=ans-res; } cout<<fans<<endl; return 0; }
相关文章推荐
- AtCoder Regular Contest 077 E - guruguru
- AtCoder Regular Contest 077 E - guruguru(贪心+差分标记)
- AtCoder Regular Contest 077 E - guruguru
- AtCoder Regular Contest 077 E - guruguru 二阶差分
- AtCoder Regular Contest 066 F Contest with Drinks Hard
- AtCoder Regular Contest 073 F - Many Moves 线段树优化dp
- AtCoder Regular Contest D - Remainder Reminder 取余问题
- AtCoder Regular Contest 092 C - 2D Plane 2N Points 贪心 匈牙利算法模板
- AtCoder Regular Contest 092(部分)
- AtCoder Regular Contest 079-E - Decrease (Judge ver.)
- AtCoder Regular Contest 058 C (水题)
- 【2-SAT】【优化连边】【AtCoder Regular Contest 069 F】Flag
- Atcoder Regular contest 085F NRE 线段树+DP
- AtCoder Regular Contest 068 E - Snuke Line 离线+树状数组
- Atcoder Regular Contest 074 F Lotus Leaves
- AtCoder Regular Contest D - Remainder Reminder 取余问题
- 【AtCoder Regular Contest 092】C.2D Plane 2N Points(匈牙利算法/tuple+set 贪心)
- AtCoder Regular Contest 092 C - 2D Plane 2N Points 贪心 匈牙利算法模板
- Atcoder Regular Contest 092 A 的改编
- AtCoder Regular Contest 080 F - Prime Flip 二分图匹配+哥德巴赫猜想