Codeforces Round #707 實錄


睡眠不足啊,午睡也沒補好,馬上迎來又一場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】


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM