牛客練習賽 16
在各位ak的大佬中,我感覺我寄幾好菜啊。。。
題目描述
給定字符串s,s只包含小寫字母,請求出字典序最大的子序列。子序列:https://en.wikipedia.org/wiki/Subsequence
字典序:https://en.wikipedia.org/wiki/Lexicographical_order
輸入描述:
一行一個字符串s (1 <= |s| <= 100,000)。
輸出描述:
字典序最大的子序列。示例1
輸入
ababba
輸出
bbba示例2
輸入
abbcbccacbbcbaaba
輸出
cccccbba
A是IQIYI筆試題。。233 。我們讓循環一開始的起始位置為$ 0 $。然後做$26$次循環,從‘Z‘到‘A‘。若當前循環的字符為$k$,我們從起始位置開始找所有出現的字符$k$,每出現一次就加到答案字符串末尾,然後更新起始位置為當前位置。這樣構造出的一定是字典序最大的字符串。
1 #include<bits/stdc++.h> 2 #define clr(x) memset(x,0,sizeof(x)) 3 #define clr_1(x) memset(x,-1,sizeof(x)) 4 #define mod 1000000007 5 #define LL long long 6 #define INF 0x3f3f3f3f 7 using namespace std; 8 string s,ans; 9 int pos,p; 10 int main() 11 { 12 ios::sync_with_stdio(false); 13 cin>>s;View Code14 pos=0; 15 for(char p=‘z‘;p>=‘a‘;p--) 16 { 17 for(int i=pos;s[i];i++) 18 { 19 if(s[i]==p) 20 { 21 ans+=p; 22 pos=i; 23 } 24 } 25 } 26 cout<<ans<<endl; 27 return 0; 28 }
題目描述
街上有n棵樹,標號為1...n,第i棵樹的高度為ai。定義這n棵樹是漂亮的,當且僅當
1. 對於所有的i,ai=an-i+1;
2. 對於1 <= i < n / 2 (不是整除),ai + 1= ai + 1;
比如說 “2 3 4 5 5 4 3 2”和“1 2 3 2 1”是漂亮的而“1 3 3 1”和“1 2 3 1”不是。
現在請問最少修改幾棵樹的高度(可以變大也可以變小),使得這些樹是漂亮的。
輸入描述:
第一行一個整數n表示樹的數量( 1 <= n <= 100,000)。i
第二行n個整數表示樹的高度( 1 <= a
<= 100,000)。
輸出描述:
輸出一個整數表示最少修改樹的高度的數目。示例1
輸入
3 2 2 2
輸出
1示例2
輸入
4 1 2 2 1
輸出
0
我們先考慮前$ \frac{n+1}{2} $ 的數字,由於$a_i-a_{i-1}=1 $,所以必須調成遞增的差值為$1$的遞增序列。我們最樸素的想法是先確定$a_1$的值,對於不同的$ a_1=k $我們算有多少個$a_i =k+i $,找最大的那個。這樣就把$ a_i $分成了幾個集合。但是這樣枚舉$k$想想會超時。但是這時你會驚奇的發現,對於在一個集合裏的元素$ a_i-i $是相同的。因此我們統計一下對於每個值$a_i-i $的數量。對於後半段的數字也是類似的操作。然後我們找這些數量的最大值$maxn$。$n-maxn$就是答案。鑒於可能出現負數,做桶排的時候下標要在加個$ P=1000000 $。
1 #include<bits/stdc++.h> 2 #define clr(x) memset(x,0,sizeof(x)) 3 #define clr_1(x) memset(x,-1,sizeof(x)) 4 #define mod 1000000007 5 #define LL long long 6 #define INF 0x3f3f3f3f 7 using namespace std; 8 const int N=1e5+10; 9 const int P=1e5; 10 int n,m; 11 int ans; 12 int a[N]; 13 int high[N*2]; 14 int main() 15 { 16 scanf("%d",&n); 17 for(int i=1;i<=n;i++) 18 scanf("%d",a+i); 19 m=(n+1)/2; 20 for(int i=1;i<=m;i++) 21 { 22 high[P+a[i]-i]++; 23 } 24 for(int i=m+1;i<=n;i++) 25 { 26 high[P+a[i]-(n-i+1)]++; 27 } 28 ans=0; 29 for(int i=1;i<=2*P;i++) 30 ans=max(ans,high[i]); 31 printf("%d\n",n-ans); 32 return 0; 33 }View Code
題目描述
平面上有若幹個點,從每個點出發,你可以往東南西北任意方向走,直到碰到另一個點,然後才可以改變方向。請問至少需要加多少個點,使得點對之間互相可以到達。
輸入描述:
第一行一個整數n表示點數( 1 <= n <= 100)。i
第二行n行,每行兩個整數x
, yi
表示坐標( 1 <= xi
, yi
<= 1000)。
y軸正方向為北,x軸正方形為東。
輸出描述:
輸出一個整數表示最少需要加的點的數目。示例1
輸入
2 2 1 1 2
輸出
1示例2
輸入
2 2 1 4 1
輸出
0
我們建個圖,對於任意兩個在同行或同列的點我們都連一條邊。如果兩點可達,那麽這兩個點一定在一個聯通塊裏。因此我們拿並查集統計下有多少聯通塊。若有$k$個聯通塊,最少加$k-1$個點把這些聯通塊連起來全部可達了。因此答案為$k-1$。
1 #include<bits/stdc++.h> 2 #define clr(x) memset(x,0,sizeof(x)) 3 #define clr_1(x) memset(x,-1,sizeof(x)) 4 #define mod 1000000007 5 #define LL long long 6 #define INF 0x3f3f3f3f 7 using namespace std; 8 const int N=1e2+10; 9 int fa[N],ans; 10 int x[N],y[N]; 11 int n,m; 12 int Find(int x) 13 { 14 if(fa[x]!=x) 15 fa[x]=Find(fa[x]); 16 return fa[x]; 17 } 18 void Union(int u,int v) 19 { 20 fa[Find(u)]=Find(v); 21 return ; 22 } 23 void init(int n) 24 { 25 for(int i=1;i<=n;i++) 26 fa[i]=i; 27 } 28 int main() 29 { 30 scanf("%d",&n); 31 init(n); 32 for(int i=1;i<=n;i++) 33 scanf("%d%d",x+i,y+i); 34 for(int i=1;i<=n;i++) 35 for(int j=1+1;j<=n;j++) 36 { 37 if(x[i]==x[j]) 38 { 39 if(Find(i)!=Find(j)) 40 Union(i,j); 41 } 42 if(y[i]==y[j]) 43 { 44 if(Find(i)!=Find(j)) 45 Union(i,j); 46 } 47 } 48 ans=0; 49 for(int i=1;i<=n;i++) 50 if(fa[i]==i) 51 ans++; 52 ans--; 53 printf("%d\n",ans); 54 return 0; 55 }View Code
題目描述
給定n個數字a1, a2, ..., an。定義f(l, r) = al | al+1| ... | ar。
現在枚舉(1 <= l <= r <= n),問不同的f值一共有多少個。
輸入描述:
第一行一個整數n表示數組大小 (1 <= n <= 100,000);i
第二行n個整數滿足0 <= a
<= 1000,000。
輸出描述:
輸出一個整數表示不同的f值一共有多少個。示例1
輸入
3 1 2 0
輸出
4示例2
輸入
10 1 2 3 4 5 6 1 2 9 10
輸出
11
E的話我們把數按二進制分成$20$位,因此我們現在有兩維,一維是序列,一維是數位。我們先要計算一下在當前下標為$i$的位置,每個數位$k$最後一次出現的下標位置,這個可以遞推解決。之後後我們做一下前綴或$pre[i]$ (跟前綴和差不多)。
然後我們接下來固定區間右端點$r$,然後找不同的$l$的情況下會產生的數。這樣的數最多$ 20 $個。一開始我們的數是$[1,r]$ 或後的結果,也就是$pre[r]$。我們前面算過下標為$r$,數位$k$出現的最晚位置,那麽我們把這些位置和數位按照位置的前後順序排序,然後把這些數位按前後順序從$pre[r]$中從$1$變為$0$,這個排序+亦或解決。當然位置相同的必須同時變換。然後每次變換以後看看這個數字是否出現過,沒有答案$+1$。因此我們還要寫一個標記數組來確認數字是否出現過。
對了還要特判一下$0$有沒有在序列中出現過,有的話答案$ +1 $。
因此綜合一下復雜度差不多$ O(n \ 20 \ log_2 20)$。後面$ 20log_2 20 $是排序的復雜度。
1 #include<bits/stdc++.h> 2 #define clr(x) memset(x,0,sizeof(x)) 3 #define clr_1(x) memset(x,-1,sizeof(x)) 4 #define mod 1000000007 5 #define LL long long 6 #define INF 0x3f3f3f3f 7 #define mp(x,y) make_pair(x,y) 8 using namespace std; 9 const int N=1e5+10; 10 const int M=5e6+10; 11 int a[N]; 12 int pre[N]; 13 int head[N][32]; 14 struct pa 15 { 16 int pre,bit; 17 }st[32]; 18 bool vis[M]; 19 int n,m,k,p,tot; 20 int ans; 21 bool cmp(pa a,pa b) 22 { 23 return a.pre<b.pre; 24 } 25 int main() 26 { 27 scanf("%d",&n); 28 ans=0; 29 for(int i=1;i<=n;i++) 30 { 31 scanf("%d",a+i); 32 if(a[i]==0) 33 { 34 vis[0]=1; 35 ans++; 36 } 37 pre[i]=(pre[i-1]|a[i]); 38 p=a[i]; 39 for(int k=0;k<32;k++) 40 { 41 if(p&1) 42 head[i][k]=i; 43 else 44 head[i][k]=head[i-1][k]; 45 p>>=1; 46 } 47 } 48 for(int i=1;i<=n;i++) 49 { 50 for(int k=0;k<32;k++) 51 st[k]=(pa){head[i][k],k}; 52 sort(st,st+32,cmp); 53 p=pre[i]; 54 for(int j=0;j<32;j++) 55 { 56 if(st[j].pre==0) 57 continue; 58 if(j==0 || st[j].pre!=st[j-1].pre) 59 { 60 if(!vis[p]) 61 { 62 ans++; 63 vis[p]=1; 64 } 65 } 66 p^=(1<<st[j].bit); 67 } 68 } 69 printf("%d\n",ans); 70 return 0; 71 }View Code
題目描述
給定n個數,從中選出三個數,使得最大的那個減最小的那個的值小於等於d,問有多少種選法。輸入描述:
第一行兩個整數n,d(1 <= n <= 100,000,1 <= d <= 1000,000,000);i
第二行n個整數滿足abs(a
) <= 1,000,000,000。數據保證a單調遞增。
輸出描述:
輸出一個整數表示滿足條件的選法。示例1
輸入
4 3 1 2 3 4
輸出
4示例2
輸入
4 2 -3 -2 -1 0
輸出
2示例3
輸入
5 19 1 10 20 30 50
輸出
1
這也是一個水題。你先排序一下。當確定最大值為 $ a_j $時, 用lower_bound找找前面大於等於 $ a_j - d $的第一個數$ a_i $,因此我們可以在 $ [ i , j-1 ] $中任選兩個數作為一個組合,對答案的貢獻為$ C_{j-i}^2 $。
1 #include<bits/stdc++.h> 2 #define clr(x) memset(x,0,sizeof(x)) 3 #define clr_1(x) memset(x,-1,sizeof(x)) 4 #define mod 1000000007 5 #define LL long long 6 #define INF 0x3f3f3f3f 7 using namespace std; 8 const int N=1e5+10; 9 int n,d,p; 10 int a[N]; 11 LL ans; 12 int main() 13 { 14 scanf("%d%d",&n,&d); 15 for(int i=1;i<=n;i++) 16 scanf("%d",a+i); 17 sort(a+1,a+n+1); 18 ans=0; 19 for(int i=3;i<=n;i++) 20 { 21 p=lower_bound(a+1,a+i,a[i]-d)-a; 22 if(p<=i-2) 23 ans+=(LL)(i-p)*(i-p-1)/2; 24 } 25 printf("%lld\n",ans); 26 return 0; 27 }View Code
牛客練習賽 16