天天考試之後好不容易有一天拿着題解打完了三道題。
嗯,談成績傷感情,只看最後有沒有掌握好了。
我差不多是一條死魚了。。。。。
上題。
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,是一個時代的終結。