暑期集訓test4

天天考試之後好不容易有一天拿着題解打完了三道題。
嗯,談成績傷感情,只看最後有沒有掌握好了。
我差不多是一條死魚了。。。。。
上題。

1.Permut

題目描述

求由 1 到 n 一共 n 個數字組成的所有排列中,逆序對個數爲 k 的有多少個。

輸入格式

第一行爲一個整數 T ,爲數據組數。
以下 T 行,每行兩個整數 n,k,意義如題目所述。

輸出格式

對每組數據輸出答案對 10000 取模後的結果。

樣例數據

輸入 
1
4 1
輸出
3

備註

對於 30% 的數據,滿足:n≤12;
對於所有數據,滿足:n≤1000, k≤1000,T≤10。

就是求逆序對,加了DP的思想。
然而狀態轉移方程太虐,一點想錯全盤皆輸。
如下。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#define mod 10000
using namespace std;

int t,n,k;
int f[1008][1008];

int main()
{
    cin>>t;
    for(int s=1;s<=t;s++)
    {
        memset(f,0,sizeof(f));
        cin>>n>>k;
        for(int i=0;i<=n;++i) 
            f[i][0]=1;               //初始化
        for(int j=1;j<=k;++j) 
            f[0][j]=1;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=k;++j)
                if(j<i) 
                    f[i][j]=(f[i][j-1]+f[i-1][j])%mod;
                else 
                    f[i][j]=(f[i][j-1]+f[i-1][j]-f[i-1][j-i]+mod)%mod;//加mod再%mod,不造成影響,將答案轉爲正數 

        cout<<(f[n][k]-f[n][k-1]+mod)%mod<<endl;
    }
    return 0;
}

對就是上面那個方程,分類討論了的那個。

2.Beautiful

題目描述

一個長度爲 n 的序列,對於每個位置 i 的數 ai 都有一個優美值,其定義是:找到序列中最長的一段 [l,r] ,滿足 l≤i≤r,且 [l,r] 中位數爲ai(我們比較序列中兩個位置的數的大小時,以數值爲第一關鍵字,下標爲第二關鍵字比較。這樣的話 [l,r] 的長度只有可能是奇數),r-l+1 就是 i 的優美值。
接下來有 Q 個詢問,每個詢問 [l,r] 表示查詢區間 [l,r] 內優美值的最大值。

輸入格式

第一行輸入 n 。
接下來 n 個整數,代表 ai。
接下來 Q ,代表有 Q 個區間。
接下來 Q 行,每行兩個整數 l,r (l≤r),表示區間的左右端點。

輸出格式

對於每個區間的詢問,輸出答案。

樣例數據

輸入
8
16 19 7 8 9 11 20 16
8
3 8
1 4
2 3
1 1
5 5
1 2
2 8
7 8

輸出
7
3
1
3
5
3
7
3

備註

【數據規模】
對於 30% 的數據,滿足:n,Q≤50;
對於 70% 的數據,滿足:n,Q≤2000;
對於所有數據,滿足 n≤2000;Q≤100000;ai≤200 。

當時做題的時候,首先排序就忽略了第一第二關鍵字,一團糟。
對於題目信誓旦旦的說一定是奇數一臉懵,不知所云。
好不容易寫出來卻發現自定義函數。。。。。嗯咳
上代碼。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

int n,q;
int a[2005],w[2005],ll[4010],rr[4010];

inline void zql()
{
    for(int i=1;i<=n;i++)
    {
        memset(ll,-1,sizeof(ll));
        memset(rr,-1,sizeof(rr));
        ll[n]=0;rr[n]=0;
        int cnt=0;
        for(int j=i-1;j>=1;j--)
        {
            if(a[j]>a[i])
                cnt++;
            else
                cnt--;       //將大於看成是++,小於看成是--。
            ll[n+cnt]=i-j;
        }
        cnt=0;
        for(int j=i+1;j<=n;j++)
        {
            if(a[j]>=a[i])
                cnt++;
            else
                cnt--;
            rr[n+cnt]=j-i;
        }
        for(int j=1-i;j<=i-1;j++)
            if(ll[n+j]>=0&&rr[n-j]>=0)
                w[i]=max(w[i],ll[n+j]+rr[n-j]+1);
    }
}

int main()
{
    //freopen("beautiful.in","r",stdin);
    //freopen("beautiful.out","w",stdout);

    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    zql();       //求每個數的優美值。
    cin>>q;
    while(q--)
    {
        int l,r;
        cin>>l>>r;
        int ans=0;
        for(int i=l;i<=r;i++)
            ans=max(ans,w[i]);
        cout<<ans<<endl;
    }
    return 0;
}

所以記錄兩邊數的大小可以用+1或是-1的方式。

3.Subset

題目描述

一開始你有一個空集,集合可以出現重複元素,然後有 Q 個操作:
1. add s
在集合中加入數字 s 。
2. del s
在集合中刪除數字 s 。保證 s 存在。如果有多個 s,只刪除一個即可。
3. cnt s
查詢滿足 a&s=a 條件的 a 的個數。

輸入格式

第一行一個整數 Q 接下來 Q 行,每一行都是 3 個操作中的一個。

輸出格式

對於每個 cnt 操作輸出答案。

樣例數據

輸入
7
add 11
cnt 15
add 4
add 0
cnt 6
del 4
cnt 15

輸出
1
2
2

備註

【數據規模】
對於 30% 的數據滿足:1≤n≤1000;
對於 100% 的數據滿足:1≤n≤200000;0<s<2^16 。

顯然題目清楚地指明瞭方向,只需要打出三個操作。
然而加粗的哪句話,當時並沒有出現。(這就不能怪我了(攤手))
還有那個 真·神神祕祕·不知道是什麼·讓人一臉懵·a.
手動微笑。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
using namespace std;

int n,k,k1,k2;
int a[260][260];
long long ans=0; 
char s[10];

int main()
{
    //freopen("subset.in","r",stdin);
    //freopen("subset.out","w",stdout);

    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        cin>>k;
        if(s[0]=='a')
        {
            k1=k/256;
            k+=256;
            k2=k%256;
            for(int j=0;j<=255;j++)
                if((j&k1)==k1)
                    a[j][k2]++;
        }   
        else if(s[0]=='d')
        {
            k1=k/256;
            k+=256;
            k2=k%256;
            for(int j=0;j<=255;j++)
                if((j&k1)==k1)
                    a[j][k2]--;
        }
        else
        {
            ans=0;
            k1=k/256;
            k+=256;
            k2=k%256;
            for(int j=0;j<=255;j++)
                if((j&k2)==j)
                    ans+=a[k1][j];
            cout<<ans<<endl;        
        }
    }   
    return 0;   
}

首先看數據範圍,我們可以將其分成√n個塊,每一次加減操作在每一個塊中同時進行,而查詢只需要在特定的塊裏查詢,依舊是√n的複雜度。
總複雜度O(√n*√n).
(256=2^8)

來自2017.7.11.的test4 >o<

——我認爲return 0,是一個時代的終結。

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