1. 程式人生 > 實用技巧 >【考試反思】聯賽模擬測試15 To be continued

【考試反思】聯賽模擬測試15 To be continued

建議改成:凱爹吊打 std

凱爹被卡常了,可惡啊。

基礎篇,但成功暴露了基礎很薄弱。T4 LCIS 完全沒思路。

T1: 90 \(\rightarrow\) 80

T1:遊戲

對自己暴力太自信了,想資料點分治,但顯然 \(O(10!\cdot 10)\) 顯然是跑不過 500ms的。= =

其實也不好意思說是掛分,因為是亂搞的水了很多分。對拍大概每 3000,4000 組就掛了,但是資料太水,就很偷稅

正解是和之前的哪一天她能重回我身邊類似,但沒有疾患鼠的情況所以更簡單。同樣兩個值連邊,統計聯通塊大小。

T2:嘟嘟嚕

約瑟夫問題,但顯然線性是過不去的。

打表發現(建議 \(m\) 取 4,很容易找到規律),只有過了一段區間之後才會出現取模的情況,那就是目前的值比下標大的時候。那麼我們顯然可以計算出下次跳到需要取模的位置。

設下一次需要跳 \(x\) 步,目前的值是 \(a\),那麼可以得到:

\[i+x<a+m\times x \]

首先注意一定是小於,因為正好相等的時候是不能取模的,因為實際上正好相等的時候對應到 \(0\)~\(n-1\) 的編號是比下標小的。

簡單移項改等號解得:

\[x=\bigg\lceil \cfrac{i-a}{m-1} \bigg\rceil \]

那麼下次的下標就是 \(i+x\)。相等的時候需要特判一下,懂的都懂。

最後剩下的部分直接加上就好了。小於 \(m\) 的部分直接暴力。

時間複雜度 \(O(能過)\)

當然前提是你要會線性解決約瑟夫問題的式子,可以看前幾天的拿道題。

Code
#include <bits/stdc++.h>
using namespace std;

inline int read(){
    int x=0;bool fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return fopt?x:-x;
}

int main(){
#ifndef LOCAL
    freopen("mayuri.in","r",stdin);
    freopen("mayuri.out","w",stdout);
#endif
    int T=read();
    while(T--){
        int n=read(),m=read(),x=0,i=m;
        for(register int j=2;j<=min(n,m);j++){
            x=(x+m)%j;
        }
        if(n<=m)printf("%d\n",x+1);
        else{
            x+=1;//記得+1!
            while(1){
                int nxt=i+(int)ceil(1.0*(i-x)/(m-1));
                if(nxt>n)break;
                x=(x+(nxt-i)*m);
                if(x==nxt){
                    if(++nxt>n)break;
                    x=(x+m)%nxt;
                }else x%=nxt;
                i=nxt;
            }
            x+=(n-i)*m;
            printf("%d\n",x);
        }
    }
    return 0;
}

T3:天才紳士少女助手克里斯蒂娜

好像直接改改式子,就能用線段樹區間加區間求和了。但是 T2 調了太久,所以本題 10 min 走人= =。

T4:鳳凰院凶真

LCIS 並輸出方案,爺不會(wtcl)。