CodeForces - 731D 80-th Level Archeology(线段树+暴力/差分)
題目鏈接:點擊查看
題目大意:給出 n 個數(shù)列,再給出一個模數(shù) mod,每次操作可以將所有的數(shù)字進行:x = x %mod + 1 操作,問至少進行多少次操作,才能使得 n 個數(shù)列按照字典序非降序排列
題目分析:思維不夠暴力來湊。。感覺很像是威海線段樹維護哈希暴力取模的那個題,事實證明是可以類比過去的
先說我的思路,對于任意兩個相鄰的數(shù)列來說,先找出其首個不相同的位置 pos,然后記錄一下其值,在代碼中我記做了 a 和 b,因為對于這兩個數(shù)列來說,a 和 b 的大小關(guān)系就直接決定了這兩個數(shù)列的相對大小關(guān)系,所以只需要關(guān)注這里即可
然后用線段樹維護一下這最多 n - 1 個大小關(guān)系,也就是每個節(jié)點維護一下每個關(guān)系中 b - a 的值,因為我們想要使得 n 個數(shù)按照字典序非降序排列,也就是所有的 a <= b ,也就是 b - a >= 0,此時我們就可以暴力枚舉更新次數(shù),每次將所有的 a 和 b 都加一,此時考慮三種情況:
不難看出每個關(guān)系中的 a 和 b 至多更新一次,因為暴力枚舉更新次數(shù)的話只需要枚舉 [ 0 , mod - 1 ] 就足夠了,所以對于每個位置維護一個變量?mmin 用來記錄當(dāng)前節(jié)點還剩幾次 “加一操作” 后才需要更新即可,這樣均攤時間復(fù)雜度是 O( nlogn ) 的
然后去網(wǎng)上看了題解,發(fā)現(xiàn)果然有簡單做法,那就是更需要思維的差分
依然是借助上文中的 a 和 b 繼續(xù)講,對于一對相對大小關(guān)系 ( a , b ) 來說,仍然是分兩種情況討論一下:
所以我們只需要找到某一個更新次數(shù) i ,使得此時差分數(shù)組的前綴和等于 n - 1 就好了
代碼:
線段樹+暴力
//#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;int n,m;vector<int>a[N];vector<pair<int,int>>node;struct Node {int l,r;int mmin;//最小更新時間int delta;//b-aint a,b;int lazy;//最小更新時間的lazy }tree[N<<2];void pushup(int k) {tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);tree[k].delta=min(tree[k<<1].delta,tree[k<<1|1].delta); }void pushdown(int k) {if(tree[k].lazy){int lz=tree[k].lazy;tree[k].lazy=0;tree[k<<1].lazy+=lz;tree[k<<1|1].lazy+=lz;tree[k<<1].mmin+=lz;tree[k<<1|1].mmin+=lz;} }void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;tree[k].lazy=0;if(l==r){int a,b;tie(a,b)=node[l-1];tree[k].mmin=min(m-a+1,m-b+1);tree[k].delta=b-a;tree[k].a=a;tree[k].b=b;return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k); }void update() {tree[1].mmin--;tree[1].lazy--; }void update(int k) {if(tree[k].mmin>0)return;if(tree[k].l==tree[k].r){if(tree[k].a>tree[k].b){tree[k].b+=m-tree[k].a+1;tree[k].a=1;tree[k].delta=tree[k].b-tree[k].a;tree[k].mmin=m-tree[k].b+1;}else{tree[k].a+=m-tree[k].b+1;tree[k].b=1;tree[k].delta=tree[k].b-tree[k].a;tree[k].mmin=m-tree[k].a+1;}return;}pushdown(k);update(k<<1);update(k<<1|1);pushup(k); }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int num;scanf("%d",&num);for(int j=1;j<=num;j++){int x;scanf("%d",&x);a[i].push_back(x);}}for(int i=2;i<=n;i++)//查找相鄰兩個數(shù)列中的a和b{bool flag=(a[i-1].size()>a[i].size());for(int j=0;j<min(a[i].size(),a[i-1].size());j++){if(a[i][j]==a[i-1][j])continue;node.push_back(make_pair(a[i-1][j],a[i][j]));flag=false;break;}if(flag)//特判1234和123的情況return 0*puts("-1");}if(node.empty())//沒有沖突,無需更改return 0*puts("0");build(1,1,node.size());for(int i=0;i<=m;i++){if(tree[1].delta>0)return 0*printf("%d\n",i);update();update(1);}puts("-1");return 0; }差分:
//#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;vector<int>a[N];int delta[N];int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int num;scanf("%d",&num);for(int j=1;j<=num;j++){int x;scanf("%d",&x);a[i].push_back(x);}}for(int i=2;i<=n;i++)//查找相鄰兩個數(shù)列中的a和b{bool flag=true;for(int j=0;j<min(a[i].size(),a[i-1].size());j++){if(a[i][j]==a[i-1][j])continue;int x=a[i-1][j],y=a[i][j];if(x>y){delta[m-x+1]++;delta[m-y+1]--;}else{delta[0]++;delta[m-y+1]--;delta[m-x+1]++;delta[m]--;}flag=false;break;}if(flag){if(a[i-1].size()>a[i].size())//特判1234和123的情況return 0*puts("-1");else//特判123和1234的情況{delta[0]++;delta[m]--;}}}int sum=0;for(int i=0;i<m;i++){sum+=delta[i];if(sum==n-1)return 0*printf("%d\n",i);}puts("-1");return 0; }?
總結(jié)
以上是生活随笔為你收集整理的CodeForces - 731D 80-th Level Archeology(线段树+暴力/差分)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1454F A
- 下一篇: CodeForces - 1427C T