【CF1179 A,B,C】Valeriy and Deque / Tolik and His Uncle / Serge and Dining Room
還好題很溫柔,溫柔得我差點沒做完
文章目錄
- A:Valeriy and Deque
- 題意
- 題解
- 代碼實現
- B:Tolik and His Uncle
- 題目
- 題解
- 代碼實現
- C:Serge and Dining Room
- 題目
- 題解
- 代碼實現
A:Valeriy and Deque
題意
給定一個雙端隊列,然后給定一個operation,每一個operation可以實現以下步驟:
1.取出隊列的前兩個元素,分別是A,B。
2.如果A>B,那么A加入到這個隊列的front,B加入到back,否則A加入back,B加入front。然后給你q個詢問,每一個詢問是問你從原始數組開始執行第x次operation時,A和B分別是多少?
(2≤n≤10^5, 0≤q≤3?10^5) (0≤ai≤10^9)( 1≤mj≤10^18)
輸入輸出樣例
輸入
5 3
1 2 3 4 5
1
2
10
輸出
1 2
2 3
5 2
輸入
2 0
0 0
輸出
說明/提示
Consider all 10 steps for the first test in detail:2. [1, 2, 3, 4, 5] — on the first operation, A and B are 1 and 2 , respectively.So, 2 we write to the beginning of the deque, and 1 — to the end.
We get the following status of the deque: [2, 3, 4, 5, 1] . 3. [2, 3, 4, 5, 1] ?A=2,B=3 . 4.[3,4,5,1,2] 5. [4, 5, 1, 2, 3] 6. [5, 1, 2, 3, 4] 7. [5, 2, 3, 4, 1] 8. [5,3,4,1,2] 9. [5, 4, 1, 2, 3] 10. [5, 1, 2, 3, 4] 11. [5, 2, 3, 4, 1]?A=5,B=2 .
題解
這個q這么大,我們就不可能每一次都去重新模擬,肯定超時
那我們就來思考A,B之間的操作
顯而易見當我們循環模擬到了a數組的最大值的時候
由于沒有任何數大于它,那么它就會開始霸占整個隊列的front
而在這個時候,就開始了一個n-1的循環節,
每一次隊列的第二個都會乖乖的跑到隊列的最后等待被翻牌
這個時候我們就沒有必要一次又一次的重復這個n-1的固定循環,
可以用一個取模來進行操作,
而從頭開始模擬時未處理到Max的時候,單獨處理一下就可以了
最壞的情況就是Max在最后面n,一個for便OK,
我們的查詢用O(1)完成
所以時間復雜度就是O(q)
代碼實現
#include <cstdio> #include <queue> using namespace std; #define LL long long #define MAXN 100005 struct node {int head, tail; }change[MAXN]; int circle[MAXN]; deque < int > deq; int n, q, Max, idx; long long m; int main() {scanf ( "%d %d", &n, &q );for ( int i = 1;i <= n;i ++ ) {int x;scanf ( "%d", &x );deq.push_back ( x );if ( x > Max ) {Max = x;idx = i;}}for ( int i = 1;i <= idx;i ++ ) {int A = deq.front();deq.pop_front();int B = deq.front();deq.pop_front();change[i].head = A;change[i].tail = B;if ( A > B ) {deq.push_front( A );deq.push_back ( B );}else {deq.push_front( B );deq.push_back ( A );}}for ( int i = 0;i < n - 1;i ++ ) {circle[i] = deq.back ();int A = deq.front();deq.pop_front();int B = deq.front();deq.pop_front();deq.push_front( A );deq.push_back ( B );}for ( int i = 1;i <= q;i ++ ) {scanf ( "%lld", &m );if ( m <= idx )printf ( "%d %d\n", change[m].head, change[m].tail );elseprintf ( "%d %d\n", Max, circle[( m - idx ) % ( n - 1 )] );}return 0; }B:Tolik and His Uncle
題目
你有一個n行m列的棋盤,其中第i行第j列的格子標號為(i,j)。你需要從(1,1)開始遍歷這個棋盤。每一次,如果你在(x,y),你可以選擇一個向量(dx,dy),并且移動到(x+dx,y+dy)這個格子上。
你不能離開這個棋盤,同時每一個向量只能使用一次。你的任務是合理安排自己的行走路線,使得每一個格子都只被經過一次。輸出這個方案。
n, m ( 1≤n?m≤10^6)
輸入輸出樣例
輸入
2 3
輸出
1 1
1 3
1 2
2 2
2 3
2 1
輸入
1 1
輸出
1 1
說明/提示
The vectors from the first example in the order of making jumps are (0, 2), (0, -1), (1, 0), (0, 1), (0, -2) .
題解
向量不一樣的意思是dx,dy不能同時一樣,
如:我用過1,1,就不能再用,但是可以用1,2或者3,1
我們先來思考只有一行的情況
那么肯定可以(1,1)=>(1,m)=>(1,2)=>(1,m-1)…每一次dy都在減小而且還分了正負
我們再來思考只有一列的情況,類比行
肯定也可以(1,1)=>(n,1)=>(2,1)=>(n-1,1)…每一次dx都在減小而且也分了正負
那么二維又有行又有列,怎么辦呢?
我們就行列一起跳唄!先循環行,列跳完后,行再往中間移動
(1,1)=>(n,m)=>(1,2)=>(n,m-1)…=>(1,m)=>(n,1)=>(2,1)=>(n-1,m)…
最后特別判斷n為奇數,m為奇數的情況即可
代碼實現
這道題就是找到了方法直接暴力就可以了
代碼可以長得五花八門
我就對自己的代碼很不滿意,有點丑!
但是是自己打的,能怎么辦呢?跪著也要寵下去麻痹自己其實寫得還不錯 !
C:Serge and Dining Room
題目
給你n個物品(每個物品一個)的價格和m個現在依次排在隊里的人手上的錢,每個人都會盡可能把錢用完去買一樣東西,即買當前物品中能買的價值最高的,不能買就不買走人,問m個人排完之后剩下的價值最高的物品價格是多少。
有q次操作,輸入操作方案
1.如果是1,輸入i,x,把ai變成x,i≤n
2.如果是2,輸入i,x,把bi變成x 1≤i≤m
( 1≤n,m≤300000 )(1≤ai, bi≤10^6) (1≤q≤300000 ) ( 1≤x≤10^6)
題解
如果在更改某個值后發現,ai<aj但是ai選的菜bi>aj選的菜bj,那么肯定要交換
換過去換過來,你會發現下標早已經打亂,所以我們就不需要考慮用下標來做
用什么呢?
題意一句話找到一個最大的x,
使得滿足錢大于等于x的人的數量money要小于價格大于等于x的數量pirce
(好好理解!!)
我們可以讓所有ai≥物品價格x的+1,而所有bi≥人手里錢數量y的-1,
因為我們把ai和bi用相同的東西一起處理的,所以區分一下+/-1,
為什么這么做呢?想想:
當我們加入ai的時候,所有小于等于ai的aj的money都應該+1
當我們加入bi的時候,所有小于等于bi的bj的price都應該+1
而上面說過,ai和bi使用同一個東西操作,那么bi+1就意味著ai-1,
所以我們才物品價格+1,錢數-1
而我們再操作ai的時候不知道整個數組有多少aj是≤ai的,也不知道bi的情況
而我們的操作卻要把所有滿足的都進行+/-1操作,那么怎么做呢?
這時就想到了線段直接來進行對于值維護修改,直接把1~x的所有值+/-1
如果i點+1就意味著后面有一道菜的價格大于等于ai,
-1則意味著后面有一個人的錢數大于等于ai
所以才有代碼下面從1~ai修改
還不用超時,多好!再用lazy打標,優化一波!
代碼實現
#include <cstdio> #include <iostream> using namespace std; #define MAXN 300005 #define MAX 1000000 int n, m, q; int opt, idx, ip; int a[MAXN], b[MAXN]; int tree[MAX << 2]; int lazy[MAX << 2]; int maxval[MAX << 2];void push_down ( int num ) {if ( lazy[num] ) {lazy[num << 1] += lazy[num];lazy[num << 1 | 1] += lazy[num];maxval[num << 1] += lazy[num];maxval[num << 1 | 1] += lazy[num];lazy[num] = 0;} }void update ( int l, int r, int L, int R, int num, int val ) {if ( L <= l && r <= R ) {lazy[num] += val;maxval[num] += val;return;}push_down ( num );int mid = ( l + r ) >> 1;if ( L <= mid ) update ( l, mid, L, R, num << 1, val );if ( mid < R ) update ( mid + 1, r, L, R, num << 1 | 1, val );maxval[num] = max ( maxval[num << 1], maxval[num << 1 | 1] ); }int query ( int l, int r, int num ) {if ( l == r ) return l;push_down ( num );int mid = ( l + r ) >> 1;if ( maxval[num << 1 | 1] > 0 ) return query ( mid + 1, r, num << 1 | 1 );return query ( l, mid, num << 1 ); }int main() {scanf ( "%d %d", &n, &m );for ( int i = 1;i <= n;i ++ ) {scanf ( "%d", &a[i] );update ( 1, MAX, 1, a[i], 1, 1 );}for ( int i = 1;i <= m;i ++ ) {scanf ( "%d", &b[i] );update ( 1, MAX, 1, b[i], 1, -1 );}scanf ( "%d", &q );for ( int i = 1;i <= q;i ++ ) {scanf ( "%d %d %d", &opt, &idx, &ip );if ( opt == 1 ) {update ( 1, MAX, 1, a[idx], 1, -1 );update ( 1, MAX, 1, ip, 1, +1 );a[idx] = ip;}else {update ( 1, MAX, 1, b[idx], 1, +1 );update ( 1, MAX, 1, ip, 1, -1 );b[idx] = ip;}if ( maxval[1] > 0 ) printf ( "%d\n", query ( 1, MAX, 1 ) );else printf ( "-1\n" );}return 0; }好了,今天的題比較容易理解,仙女最近被幾道ex至極的題給卡住了,
博客有點男鞋,不要急,慢慢來!有任何問題都可以留言!
不要太想小哥哥我~~
總結
以上是生活随笔為你收集整理的【CF1179 A,B,C】Valeriy and Deque / Tolik and His Uncle / Serge and Dining Room的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: winhex怎么使用
- 下一篇: 插座最全使用指南插座最全使用指南图解