1. 程式人生 > >2016-8-4夏令營入營測試總結

2016-8-4夏令營入營測試總結

本次的測試從思維和程式設計角度上來說都是很簡單的,然而在時間上卻並不簡單。雖然說我們現在的水平已經相當不錯,但是考的仍然不是很好,估計是久離演算法的緣故了。

題目的連結是http://pan.baidu.com/s/1hrIQMry
【T1:音階】
這題很水,直接做吧,只不過要注意題目中是“最後一個音符”而不是“最後一節的重音”。

/*
A MT : A D E
C MT : C F G
*/
# include <cstdio>
# include <cstring>
using namespace std;
const int MAXL = 120;
char
music[MAXL]; int A_MT,C_MT; int main(){ freopen("ljestvica.in","r",stdin); freopen("ljestvica.out","w",stdout); scanf("%s",music); int len = strlen(music); bool nowisFirst = true; A_MT = C_MT = 0; for (int i=0;i<len;++i){ if (nowisFirst){ if (music[i] == 'A'
|| music[i] == 'D' || music[i] == 'E') ++A_MT; if (music[i] == 'C' || music[i] == 'F' || music[i] == 'G') ++C_MT; } if (music[i] == '|') nowisFirst = true; else nowisFirst = false; } if (A_MT == C_MT) if (music[len-1] == 'C' || music[len-1] == 'F'
|| music[len-1] == 'G') printf("C-dur"); else printf("A-mol"); else if (A_MT > C_MT) printf("A-mol"); else printf("C-dur"); return 0; }

【T2:波老師】
真是奇怪的題目……好吧這題有個很簡單的暴力,就是O(n2)的,但是用一點常數的優化就多過了20%的資料……那資料的範圍可是從1000106啊……好吧不吐槽出題人了,先放程式:

# include <algorithm>
# include <cstring>
# include <cstdio>
# include <cmath>
using namespace std;
const int MAXN = 2000010;
pair<int,int> Point[MAXN];
int T;
int n,m;
/*Water!*/
//int MLen[MAXN*MAXN];
bool f[MAXN];
bool found;
//int size = 0;

int main(){
    freopen("teacher.in","r",stdin);
    freopen("teacher.out","w",stdout);
    scanf("%d",&T);
    for (int kase = 0 ; kase < T ; ++kase){
        /*Initial*/
        memset(f,false,sizeof(f));
    //  size = 0;

        scanf("%d%d",&n,&m);
        for (int i=0;i<n;++i){
            scanf("%d%d",&Point[i].first,&Point[i].second);
        }
        sort(Point+0,Point+n);
        /*Water!*/
        found = false;
        for (int i=0;i<n;++i){
            for (int j=0;j<i;++j){
                int dis = abs(Point[i].first-Point[j].first)+abs(Point[i].second-Point[j].second);
                if (f[dis]){
                    found = true;
                    break;
                }
                else f[dis] = true;
            }
        }

        /*
        bool found = false;
        sort(MLen+0,MLen+size);
        for (int i=1;i<size;++i){
            if (MLen[i] == MLen[i-1]){
                found = true;
            }
        }
        */

        if (found) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

好吧另外補一下,其實這其中有用到鴿巢原理的……考慮到,其實只有最多2×106種的不相同的曼哈頓距離,所以這個break就使得時間複雜度變成了O(min(n2,2×m))!確實,有是一個break就有神效。

【T3:爆裂吧世界】
先吐槽一下名字~出題人沒有改過來吧。好吧,這題的思維難度比較大,而我是在臨考試結束前十幾分鍾時想出來的,根本沒有時間編了~然而我的想法和出題人的一樣……
好吧不說廢話了,這道題目題面已經足夠明晰,那麼對於其的做法,我們先要參考一下逆序對的樹狀陣列解法,在這裡我們可以知道如何求出在第i個數前面並且比第i個數小的數的個數了,而且以此類推還可以求出在第i個數後面的那些啊,比第i個數小的那些啊……
總之很簡單。那麼我們考慮一下這個能幹什麼。考慮將這個四元組(a,b,c,d)分成兩個雙元組(a,b)(c,d),然後我們統計第i個數分別作為其中的abcd,並分別求方案數。那麼,我們先想想看,如果我們求出兩個雙元組各自的方案數,再乘起來,得到的是答案嗎?顯然不是,因為題目要求abcd,但是直接應用乘法原理很有可能會使得不等號不成立。那麼怎麼辦呢?減掉等於的部分!怎麼減呢?容斥原理!先考慮沒有限制的,就是乘法原理直接乘,然後有兩個互相相等的有6種情況,但是可以排除掉兩種,a=bc=d,因為本身我們求方案數的時候就沒有這兩種情況。同理,三個和四個互相相等的都一定會有這種情況,所以都會排除。如果用P{...}來表示相應的方案數,那麼有

P{abcd}=P{a?b?c?d}P{a=c}P{a=d}P{b=c}P{b=d}
然後相應求出來就好了。怎麼求呢?這裡以P{a=c}為例,如果a=c,那麼我們現在要的就是先列舉一個i,然後統計另外獨立存在的bd,也就是分別將i作為ac,統計相應的(i,b)(i,d)的方案數,由於其獨立存在,所以用乘法原理乘起來就好了。像(i,b)的方案數實際上就是在第i個數後面並且比第i個數大的數的個數,其餘以此類推,我們就可以求出P{a=c}=i=1nP{i,b}×P{i,d},其餘的幾個也可以用類似的方法求出。
於是便求完了,程式碼如下:
/*
目前並沒有寫完,稍後補上
*/

其實這道題並不難,只是程式碼量有點大,不是那種能在5分鐘內編完的型別……