1. 程式人生 > 實用技巧 >2020-12-30 Actor 趣題

2020-12-30 Actor 趣題

由周指導提供的高質量好題。

A

非常的妙,考慮一個數二進位制拆分以後,可以經過不超過 \(\log n\)\(\ll\)\(\ll +1\) 得到任意一個 \(n\) 以內比自己大的數。

但是由於有比自己小的數,所以我們要將連出的點的序號對 \(n\) 取一下模,這樣就能把 \(x\to y\) 轉化成 \(x\to y+n\)

兩種情況都是能保證轉移長度小於 \(n\) 的,那麼這樣便可以保證次數 \(\le 10\)

int main()
{
    int i,j;
    int n=rin();
    for(i=1;i<=n;i++)printf("%d %d\n",((i<<1)-1)%n+1,((i<<1)%n+1);
    return 0;
}

C

顯然,若是柱子數大於 \(20\),必然 B 勝。

然後考慮 DP,發現每兩次加柱子操作之間的移動次數 \(x\),會對答案進行一次貢獻,具體的:\(v\to \min{\lceil\frac{v}{2}\rceil,x+1}\)

會發現這個東西不方便實現,但是若是倒著考慮,便會變得簡單,可以直接字首和優化 DP。


F

考慮到這個式子非常的噁心,我們需要將其轉化一下。

對於模數,我們可以求出它的原根 \(g\),那麼每個 \(a_i\) 都可以表示成 \(g^{b_i}\) 的形式,式子中的那部分就可以寫成 \(g^{b_i+b_j}\pmod p\)

那麼就可以大力 FFT 求解。

我 WA 了六發,我是 sb,這道題我都找到不用罰時的提交的地方了還傻乎乎地交正在進行的比賽

  • 我的 FFT 被周指導和 hehezhou 怒 D,求完單位根然後乘乘乘非常的愚蠢,精度並不高。應當每次重新拿 \(cos,sin\) 去算,多次呼叫的話就應當預處理好。

  • 我又犯傻了,記錯了費馬小定理,\(x^{p-1}\equiv 1\),不應當再記錯了。

int main()
{
    int i,j;
    int s=1;
    for(i=0;i<=2e5+2;i++,s=1LL*s*K%P)Num[s]=i;
    
    n=rin();
    LL sum=0;
    for(i=1;i<=n;i++)
    {
        int x=rin();
        if(!x){n--;i--;continue;}
        a[Num[x]].a++;
        sum-=1LL*x*x%P;
    }
    
    init((P<<1)+1);
    FFT(a,1);for(int i=0;i<lens;i++)a[i]=a[i]*a[i];FFT(a,-1);
    s=1;
    for(int i=0;i<lens;i++,s=1LL*s*K%P)sum+=1LL*s*((long long)(a[i].a+0.5));
    sum>>=1;
    printf("%lld\n",sum);
    return 0;
}

G

證明出結論以後,就非常 Simple 了。

證明的過程,就按照周指導所說的,考慮每次必定可以選取一對相鄰的匹配的將問題規模減 \(2\)

int main()
{
    int i,j;
    int n=rin();
    LL ans=0;
    for(i=1;i<=n;i++)a[i]=rin(),ans+=a[i];
    for(i=1;i<=n;i++)d[i&1].push(rin()-a[i]);
    n>>=1;
    for(i=1;i<=n;i++)
    {
        LL nows=d[0].top()+d[1].top();
        if(nows<=0)break;
        ans+=nows;
        d[0].pop_front();
        d[1].pop_front();
    }
    printf("%lld\n",ans);
    return 0;
}

I

首先預處理出前 \(i\) 種數,總和為 \(j\) 的方案數,萬老爺教了我 \(\operatorname O(n\cdot |S|)\) 的做法。

然後列舉平均數 \(x\),這個時候,可以將所有數的貢獻轉化一下,然後得到了 \(f(x-1)=f(n-x)\) 的式子,於是可以暴力枚值域,複雜度和預處理一樣。

我陣列開小 WA 掉了???又貢獻了罰時。

int main()
{
    int i,j,_,cts;
    int sum=0;
    int l,r;
    n=rin();k=rin();m=rin();
    f[0][0]=1;
    for(i=1;i<=n;i++)
    {
        int nows=sum+k*i;
        for(j=0;j<i;j++)
        {
            tail=0;
            for(_=j;_<=sum;_+=i)tail++,add[tail]=(add[tail-1]+f[i-1][_])%m;
            if(!tail)continue;
            for(_=j,cts=0,l=1,r=1;_<=nows;_+=i)
            {
                f[i][_]=(add[r]-add[l-1]+m)%m;
                cts++;
                if(cts-(l-1)>k)l++;
                if((r-1)<cts&&r<tail)r++;
            }
        }
        sum=nows;
    }

    for(i=1;i<=n;i++)
    {
        LL ans=0;
        for(j=1;j<=sum;j++)ans+=(1LL*f[i-1][j]*f[n-i][j])%m;
        printf("%lld\n",(((ans%m)*(k+1)+k)%m+m)%m);
    }
    return 0;
}