睡眠不足啊,午睡也沒補好,馬上迎來又一場CF。
不做人了,我做鬼。
上次不用樣例檢驗吃了大虧。
這次不管怎么樣,都用樣例檢驗一遍。
【A】
模擬題。因為有延誤的問題,因此不一定按照期望時間表運行。
每次判斷下一次出發的時間即可。
【B】
竟然有彩圖
區間標記,差分即可。
【C】
PK題?
但這規模有點大啊
感覺只能排序 然后雙指針?
設x y z w是排序后的新下標
那么 x<z<w<y
為什么ai不是10^9?
我們倒是可以從ai入手,首先ax+ay=az+aw
變形 ax-az=aw-ay
變成差的問題,范圍[1,2.5*10^6]
枚舉這個差
但是配對的端點如果也枚舉的話就時間不夠了
轉D
調整法,可以認為區間[x,z]和[w,y]是z<w的,不穿梭
反向差分,求前綴和,那么可以轉為求兩個相等的區間和。
f[i][x]表示1~i內是否存在區間和==x
那么f[i][x]=f[i-1][x] | f[i][x-b[i]]
還是想雙指針
排序后,p和q分別在1和2
然后哪一個指針右移造成的增量小,就移動哪個,(但是單步小不能說明什么)
這樣會產生一系列配對和,記錄它們,然后——
反過來做一遍?
首先,對每種數值,記錄相應的ai
如果存在兩種數值v1和v2,其數組的size的大小都>1
那么取里面的數字下標即可。
否則,最多只有一個數值其size>1
分 有 或 沒有 討論
如果有 我們可以以2*v1為sum,然后掃一遍數組看看有無這樣的配對。O(N)
否則和 沒有 的情況一同處理
此時四個目標都不相同
再思考相鄰數字的差,一共n-1個
假設有兩個差相同,且對應的配對中數字不重復,
取它們作為答案
否則
要么所有差都不相等 或 相等的差都是 x y z (x,y) (y,z)的形式
如果所有差都不相等,那么差至少>= 0 1 2 ... n-1
a的max>=1+n*(n-1)/2
而因為ai是<=2.5*10^6的,因此這種情況下n一定是sqrt(10^6)的級別,直接枚舉配對即可。
如果有相等的差,且數量>=3個,也可以取為答案,否則最多一個三元形式。
n也是sqrt(10^6)級別的,O(N^2)處理即可。
【D】
找循環節
首先,最多n*m次,一定開始循環,最壞情況是可能達到的。兩個素數。
首先看n=m的情況
這種情況比較簡單,統計一下不同點數量c,然后k%c,就知道是哪一天會暴走。
n!=m,假設n<m
注意a數組都是不同的,b同理
我們其實只要關注k<=n*m的情況就行了。
TMD,感覺我被題目牽着走。
能不能把循環轉化成別的東西。
如果把max(n,m)天視為一輪,那么
這里就是m
第一輪我們直接復制n的循環湊齊m
然后計算不同點的數量,第二輪,其實就相當於左移n天的循環?
可是計算不同偏移下的不同點數量似乎也要n*m?
轉E
發現一個性質,因為a和b分別都是無重復元素的
因此對於b中的一個元素,最多只有一個a的元素等於它。
它們的日程碰到的時候才產生貢獻。
對於b,(注意我們以后就設b的m>a的n,否則我們交換數組a和b)
每個bi,可以確定唯一的aj=bi,記h[i]=j,可以為0
對於一個配對(aj,bi),如果某天同時訪問到它們,且,有一個bk,滿足j-k=d,
其對應的al 也滿足 j-l=d,那么這個配對(al,bk)必然在d天前也被同時訪問。
對於bi,下一輪訪問bi,對應的a指針會偏移 d=m%n
我們可以思考,從第一輪出發,多少次偏移會使得當b指針在bi時
a指針重新回到第一次的bi的對應點。
期間是否偏移到了這個bi的同數值a
這樣就可以算出這個 大輪回 中bi產生的貢獻
每個bi的大輪回長度是一樣的,即lcm(n,m)
我們看k會出現在第幾個大輪回內。
如果最后一個大輪回模擬,O(NM)
艹
或者我們O(M)枚舉最后的一天是bi(假設)
然后計算對應的——
這命運之輪,讓我想起旋轉的吊燈,沙皇,我主貝倫,
誰都擁有幸福的權利。
討論剩余系,而不是+1 +1天的觀察
對每個b,以相碰為起點觀察輪回
對於有對應同數值的a的bi,第一次相碰的天數記為fi
那么,lcm(n,m)后,bi會第二次相碰。
第w天的時候,bi產生的貢獻就是 floor((w-fi)/lcm(n,m))
所有這些加起來就是總貢獻,若等於k,這就是我們要找的w
這感覺是數論分塊。
的確,是個數論題,lcm也有。
因為k關於w的函數顯然是單調的,直接二分w。
但是最后答案輸出與正確答案總是相差1或者2.
沒時間DEBUG了,END
發現3題實時排名就300+,這場比較難?還是做的人太少了?
我猜我是 尋找第一個t使得t*d%n==c,這個過程出了錯。
以下是錯誤代碼:
#include <bits/stdc++.h> using namespace std; #define FOR(i,n) for (int i=1;i<=n;i++) #define REP(i,a,b) for (int i=a;i<=b;i++) #define pb push_back #define fi first #define se second #define pi pair<int,int> #define mp make_pair typedef long long ll; typedef complex<double> comp; const int inf=0x3f3f3f3f; const ll linf=1e18; const int N=5e5+10; const double eps=1e-10; const ll mo=998244353; int n,m; ll k; int a[N],b[N]; int p[2*N]; ll f[N]; ll T; ll gcd(ll a,ll b) { return (b==0)?a:gcd(b,a%b); } ll lcm(ll a,ll b) { return a/gcd(a,b)*b; } ll get(ll d,ll n,ll c) { c%=n; ll t1=ceil(n/d); ll u=t1*d%n; if (u==0||c%u) return -1; else return t1*c/u; } ll get(ll a,ll b) { // (t*m)%n==(a-1-b+n)%n; ll t; if (a==b) t=0; else t=get(m,n,a-b+n); return t+b; } bool check(ll w) { ll r=0; FOR(i,m) if (p[b[i]]) { if (w>f[i]&&f[i]!=-1) r+=(w-f[i])/T; } if (w-r>=k) return 1; else return 0; } int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); cin>>n>>m>>k; FOR(i,n) cin>>a[i]; FOR(i,m) cin>>b[i]; if (n>m) { swap(n,m); FOR(i,max(n,m)) swap(a[i],b[i]); } FOR(i,n) { p[a[i]]=i; } FOR(i,m) if (p[b[i]]) { if (p[b[i]]==i) f[i]=i; else f[i]=get(p[b[i]],i); } T=lcm(n,m); ll l=1,r=1e12; ll w=0,ans=0; while (l<=r) { w=(l+r)>>1; if (check(w)) { ans=w; r=w-1; } else l=w+1; } cout<<ans<<endl; return 0; }
【E】
把一個東西變為另一個東西,轉化題。
首先,你需要判斷無解,有解的必要條件:行集合應該一樣。
下一次排序為什么不會撤銷上一次排序的效果?
效果依然保留的是,那些在這次排序中數值相等但是上一次對應數值不相等的那些。
只剩1h了,回去D
枚舉最后一次操作?
【F】