1. 程式人生 > >泛刷水題記17.12.27

泛刷水題記17.12.27

SHOI的題目質量好高啊,感覺都是些不錯的題目……(我都不會做

LOJ 2142「SHOI2017」相逢是問候

題意:給定一個序列,在模p意義下,茲瓷區間對給出的一個常數c取冪(原來是ai,變成cai),以及區間求和的操作,注意p不一定是質數,ai,cp108
分析:一看到模意義,我們馬上想到指數迴圈節,由於

amam%φ(p)+φ(p)(modp)mφ(p)
我們會發現,這個定理大致意思就是說,找另一個n,使得nm(modφ(p))
那麼進一步的,再套幾層下去,就會相當於模φ(φ(p)),φ(φ(φ(p))),
很明顯O(logn)次之後就有m<模數,就是不用修改了
然後和區間取模就很類似了,利用線段樹維護暴力修改和區間求和,每次暴力修改,如果發現不用修改了(對原來指數的模已經相當於模1
了),那就不改了,否則暴力遞迴下去修改
直接做是O(mlognlog2p),因為還有快速冪的複雜度,但是我們會發現我們可以將快速冪分成兩段預處理(就像USACO某道叫牛計數的題目),對c預處理,對c10000預處理,然後就做完了,複雜度O(mlognlogp),這是很有用的技巧!

LOJ 2143「SHOI2017」組合數問題

題意:從nk個物品裡選模kr個物品,問方案數模P
分析:容易看出,如果我們設一個f(i,j)表示模k意義下前i個裡選餘j個物品,那麼很明顯可以有f(i,j)=f(i1,j)+f(i1,j1),那麼就可以矩陣乘了
但是還有更快的做法,就是考慮到f(2n,t)

i+j=tf(n,i)×f(n,j)
就是列舉前一段和後一段選的個數,時間複雜度O(k2logn)

# include <cstdio>
# include <cstring>
# define mem(x,v) memset(x,v,sizeof(x))
# define N 1000000000
# define K 50
typedef long long LL;

LL p;
int k;

struct MVec {
    LL a[K * 2];

    MVec(bool u = false) : a() {
        if (u) a[0] = 1;
    }

    LL &operator
[](int i) { return a[i]; } const LL &operator[](int i) const { return a[i]; } }; inline MVec &operator%=(MVec &a, int k) { for (int i = k; i < k * 2; i++) { (a[i - k] += a[i]) %= p; a[i] = 0; } return a; } inline MVec operator*(const MVec &a, const MVec &b) { MVec res; for (int i = 0; i < k; i++) { for (int j = 0; j < k; j++) { (res[i + j] += a[i] * b[j] % p) %= p; } } res %= k; return res; } inline MVec pow(MVec a, LL n) { MVec res(true); for (; n; n >>= 1, a = a * a) if (n & 1) res = res * a; return res; } int main() { int n, r; scanf("%d%lld%d%d", &n, &p, &k, &r); MVec a; a[1] = 1; a[0] = 1; a %= k; MVec res = pow(a, (LL)n * k); printf("%lld\n", res[r]); }

LOJ 2190「SHOI2014」訊號增幅儀

題意:平面上給一些點,問最小橢圓覆蓋,其中橢圓長軸和短軸的比是給出的一個λ,同時長軸要求固定在與x軸夾θ角的方向上
分析:這裡轉化的思路還是很茲瓷的……畢竟我們還是會最小圓覆蓋的
考慮將整個圖轉到長軸的方向上,然後將整個圖短軸方向上擴大λ(防止精度損失),然後就還是一個最小圓覆蓋辣……
最小圓覆蓋用隨機增量法很好寫……所以是期望O(n)

LOJ 2039「SHOI2015」鐳射發生器

題意:給一條射線,每次碰到一條線段i,,就會發生反射,反射角φ與入射角θ之間滿足φ=λiθ,問前10次碰到哪些線段,線段數量不多於100
分析:這是一道暴力題……直接暴力判斷肯定不會超,而且資料範圍其實可以往上放得多很多的qaq