【學術篇】辣雞出題人喫棗藥丸!!!!

辣雞出題人喫棗藥丸!!!!

2017.11.01 這是一次取得了圓滿失敗的胡策…..

T1(set): 給你n個數, 求出一個非空子集, 使這個集合元素之和爲n的倍數.
本題做法:
算法0: 輸出-1.
時間複雜度O(1) 空間複雜度O(1) 期望得分10 實際得分0.
算法1: 容易發現, 當其中有數字%n==0時, 輸出這個數即可.
時間複雜度O(n) 空間複雜度O(1) 期望得分10 實際得分50.
算法2: 對於20%的數據, n<=20
枚舉每個集合判斷即可…
時間複雜度O(2n ) 空間複雜度O(n) 期望得分20 實際得分20. 結合算法1, 得分50.
算法3: 對於50%的數據, n<=1000
dp 設f[i][j]爲前i個數的和%n等於j的情況是否存在, 狀態轉移方程如下:

f[0][0]=1;
f[i][(j+a[i])%n]=f[i-1][j];
f[i][j]=f[i-1][j]; (i!=1&&j!=0)

時間複雜度O(n2 ) 空間複雜度O(n2 ) 期望得分50 實際得分60. 結合算法1, 得分60.
算法4(正解): n<=1000000 鴿巢原理(其實對於OI來說這個原理只有這一個題)
考慮前綴和, 有n個取值, 而對於n的剩餘系, 有1~n-1這些取值, 所以至少有兩個是相同的, 把他們中間的輸出即可.
時間複雜度O(n) 空間複雜度O(n) 期望得分100 實際得分100.
代碼:

 #include <cstdio>
int a[1000010],b[1000010];
inline int gn(){
    int a=0;char c=getchar();for(;c<'0'||c>'9' ;c=getchar());
    for(;c>47&&c<58;c=getchar()) a=(a<<1)+(a<<3)+c-48; return a;
}
int main(){
    freopen("set.in","r",stdin); freopen("set.out","w",stdout);
    int n=gn(),s=0; for(int i=1;i<=n;i++) a[i]=gn()%n;
    for(int i=1;i<=n;i++){
        s=(s+a[i])%n;
        if(b[s]){ printf("%d\n",i-b[s]);
            for(int j=b[s]+1;j<=i;++j) printf("%d ",j); return 0; 
        }else b[s]=i;
    }
}

算法5(“正解”): 什麼都不輸出…
時間複雜度O(0) 空間複雜度O(0) 期望得分0 實際得分100.
這是本題時空複雜度最優的解法, 碼長也是最短的, 而出題人並沒有想到這種做法…
算法解釋:
fscanf等函數對於讀入失敗的返回值是EOF而不是0
所以判斷的時候要用~而不是!
辣雞出題人水平菜還寫spj
結果TM不輸出都能AC啊
不過終於有一道比NOIP D1T1還簡單的題了
總之辣雞出題人喫棗藥丸
下面貼代碼:

#include<cstdio>
main(){freopen("set.out","w",stdout);}

算法注意事項: 一定要寫輸出文件, 不然會報”文件錯誤”…
這題就這麼着吧…

辣雞出題人喫棗藥丸!!!!

T2: 給一個A數組, 求將這個數組排列成兩兩不相同, 至少要去掉多少元素.
而A數組的給出方式是這樣的:

//第一行讀入兩個個整數 M, K.
//接下來一行讀入 M 個整數 count[i], 其中 N=∑count[i] .
//接下來一行讀入 M 個整數 X[i].
//接下來一行讀入 M 個整數 Y[i].
//接下來一行讀入 M 個整數 Z[i].
int N = 0, S = (1 << K) - 1;
for (int i = 1; i <= M; ++i) {
    N = N + 1;
    A[N] = X[i];
    long long last = X[i];
    for (int j = 1; j < count[i]; ++j) {
        last = (last * Y[i] + Z[i]) & S;
        N = N + 1;
        A[N] = last;
    }
}
//辣雞出題人還"貼心"的加了一句:"注意:因爲生成 A[i]的方法不好用語言描述, 所以用代碼來表達. 直接照搬代碼的話後果自負.Emmmm..."

時限1s 空間16MB(夠開4M int數組)

本題做法:
算法1: 什麼都不輸出…
時間複雜度O(0) 空間複雜度O(0) 期望得分100 實際得分0. (因爲本題並沒有spj…)
好的, 我們容易看出:
我們找出出現次數最多的一個數x
排成這樣:x,a,x,b,x,c,x,…,x (a,b,c等是不等於x的數,他們可以相等
這樣很顯然答案就是x2n1
當然如果是負數就該輸出0了
算法2: subtask#1 10pts N<=20
想怎麼做怎麼做.. 就是這麼爲所欲爲..
時間複雜度O(爲所) 空間複雜度(欲爲) 期望得分10 實際得分10.
算法3: subtask#2 20pts N<=1000000
這個是能存下來的.. 隨便搞搞就出來了…
時間複雜度O(n)~O(nlogn) 空間複雜度O(n) 期望得分30 實際得分30.
算法4: subtask#3 20pts K<=20
這個可以開桶… 好像比上面的還要好做…
時間複雜度O(2^K) 空間複雜度O(2^K) 期望得分30 實際得分30 結合算法3, 得分50.
算法5(正解): subtask#4 50pts N<=50000000 K<=30
50000000…一看就是O(n)嘛… 兩遍O(n)好像都過不了吧, 辣雞出題人都喪心病狂的卡內存了, 卡個常數很正常吧…(flag√)
但是好像有一道題可以4MB找衆數來着28…(然而我並找不到鏈接了…)
聽dalao說, bzoj有一道mode的題也是這麼個東西..(然而辣雞bzoj 502 Bad Gateway了)
就是 存兩個變量p q
開始時p=-1(隨便找個不可能取到的值), q=1
然後掃, 訪問到i, 如果i==p q++ 否則q– 如果q==0 則用i替換p,q恢復爲1
這樣就可以找到出現次數最多且次數大於n2的數了
然後再掃一遍找出它的出現次數即可…
喂!!!爲什麼這樣能過啊!!!
Emmmm反正最後就是過了…也就是這麼暴力….
代碼:

#include <cstdio>
int x[1004],y[1005],z[1006],w[1007];
inline int gn(){
    int a=0;char c=getchar();for(;c<'0'||c>'9' ;c=getchar());
    for(;c>47&&c<58;c=getchar()) a=(a<<1)+(a<<3)+c-48; return a;
}
int main(){
    freopen("read.in","r",stdin); freopen("read.out","w",stdout);
    int m=gn(),k=gn(),s=(1<<k)-1,p=-1,q=1,n=0;
    for(int i=1;i<=m;++i) w[i]=gn();for(int i=1;i<=m;i++) x[i]=gn();
    for(int i=1;i<=m;++i) y[i]=gn();for(int i=1;i<=m;i++) z[i]=gn();
    for(int i=1;i<=m;++i){
        if(x[i]==p) q++; else {q--; if(!q) p=x[i],q=1;}
        long long last=x[i]; ++n;
        for(int j=1;j<w[i];++j){
            last=(last*y[i]+z[i])&s; ++n;
            if(last==p) q++; else {q--; if(!q) p=last,q=1;}
        }
    } q=0;
    for(int i=1;i<=m;++i){
        if(x[i]==p) q++; long long last=x[i];
        for(int j=1;j<w[i];++j){
            last=(last*y[i]+z[i])&s;
            if(last==p) q++;
        } //這兩遍明明就是抄的...
    } if((q=q*2-n-1)>0) printf("%d",q); else putchar(48);
}

就這樣吧…

T3我不會, 這個坑有空再填吧…

最後的最後,

——辣雞出題人喫棗藥丸!!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章