【牛客OI周赛7-普及组ABCD 非官方题解】暴力,二分,KMP,尺取(STL或Hash)
A:
鏈接:https://ac.nowcoder.com/acm/contest/372/A
來源:牛客網
?
某天,一只可愛的肥橘喵在路上走,突然遇到了一個怪人,那怪人自稱PM6,“小肥喵,這里有一道水題,答對了我就請你吃狗肉,答錯了你就請我吃貓肉!”
喵咪瑟瑟發抖:“QAQ什么題?”
PM6道:“給你坐標軸上的N個點,求出對于每個點,有多少個點的 X 坐標和 Y 坐標都大于它。”
毫不意外,蠢肥喵完全不會這道題并面臨著被做成貓肉火鍋的危險,求求你救救喵咪!
輸入描述:
輸入包括兩行,第一行是正整數n,表示點數,接下來N行每行兩個數表示第i個點的橫坐標和縱坐標,坐標值都是整數,輸入數據中存在坐標相同的點。 對于50%的數據:0<=點的坐標大小<=10000,0<=N<=100 對于100%的數據:0<=點的坐標大小<=10000,0<=N<=1000輸出描述:
輸出包括N行,第i行表示有多少個點在點i的右上方。示例1
輸入
復制
3 1 2 2 3 4 4輸出
復制
2 1 0解題報告:
? ?暴力沒啥好說的。
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e5 + 5; pair<int,int> p[MAX]; int main() {int n;cin>>n;for(int i = 1; i<=n; i++) {scanf("%d%d",&p[i].first,&p[i].second);}for(int i = 1; i<=n; i++) {int ans = 0;for(int j = 1; j<=n; j++) {if(p[j].first > p[i].first && p[j].second > p[i].second) ans++;}printf("%d\n",ans);}return 0 ;B:
題干:
鏈接:https://ac.nowcoder.com/acm/contest/372/B
來源:牛客網
?
某天,一只可愛的小兔砸在路上蹦蹦跳跳地走著,怪人PM6出現了,于是小兔子被盯上了。
PM6:“免子。哦不,小兔子。你長得真好…不對,真可愛。我這里有一道很容易很容易的題目,答對了我就請你吃蘿卜,答錯了你就請我吃兔肉,好不好呀~~?”
小兔砸:“蘿卜!?好呀好呀好呀。”于是笨笨的兔紙入套了。
PM6:“我這里有一個由 N 個數組成的序列,給你 M 個詢問,每個詢問會給你一個數 X ,對于每個詢問,你要回答出序列中與這個值最接近的元素。”
聽完題后,兔子嚇成一坨免子了,面臨著變成紅燒兔頭的危險,求求你救救兔子!
輸入描述:
第一行包含一個整數N,為序列長度。 第二行包含N個整數,為序列各元素。 第三行包含一個整數M,為PM6的詢問個數。 接下來M行,每行一個整數X,為要詢問最接近元素的給定值。 對于40%的數據:1<=N<=10000,1<=M<=1000 對于另外10%的數據:M=1 對于100%的數據:1 <=N<= 100000,1<=M<=10000,0<=序列中的每個數,X<=1e9輸出描述:
M行,每行有一個整數,為最接近相應給定值的元素值,保持輸入順序。若有多個值滿足條件,輸出最小的一個。示例1
輸入
復制
5 2 4 5 5 7 3 2 5 6輸出
復制
2 5 5解題報告:
? ?二分就好了,注意特判第一個數和最后一個數,因為這兩個不能用下面那個通式(因為可能pos-1==0 或者pos==n+1,此時不能放到數組中取對應數(因為都是0))(貌似很多人因為沒有特判所以80分了這題。。)
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e5 + 5; int a[MAX]; int main() {int n,m;cin>>n;for(int i = 1; i<=n; i++) scanf("%d",a+i);sort(a+1,a+n+1);cin>>m;while(m--) {int x;scanf("%d",&x);int pos = lower_bound(a+1,a+n+1,x) - a;if(pos == 1) {printf("%d\n",a[1]);continue;}if(pos == n+1) {printf("%d\n",a[n]);continue;}if(abs(a[pos] - x) >= abs(a[pos-1]-x)) printf("%d\n",a[pos-1]);else printf("%d\n",a[pos]);}return 0 ;}?C:
題干:
鏈接:https://ac.nowcoder.com/acm/contest/372/C
來源:牛客網
?
另一天,一只可愛的圍著圍巾的肥企鵝在路上搖搖晃晃地走著,遇上了迎面走來的打著飽嗝的PM6。小企鵝預感不妙,這不就是最近有名的惡人PM6么!嚇得立刻扭頭就想跑。
PM6:“小火汁,站住!我不吃你(誰叫你是保護動物)。我這有一道簡單題,如果你答對了,我就給你吃魚肉,如果你答錯了,就免費幫我充游戲幣!”
企鵝:“_(:3J∠)_(默默摘掉圍巾)”
PM6:“我給你一個文本串 S ,再給你兩個串A、B,你要將文本串中的 A 都轉換成 B ,轉換后的字符不再參與轉換,輸出最終的文本串。”
求求你救救企鵝!
輸入描述:
第一行輸入一個文本串 S 。 第二行輸入字符串 A 。 第三行輸入字符串 B 。 |S|為S的長度,|A|為A的長度,|B|為B的長度,所有字符都是小寫字母,保證 |A| <= |S| 。 對于50%的數據:1<= |A|、|B|、|S| <=1000 對于100%的數據:1<= |A|、|B|、|S| <=1000000輸出描述:
只有一行,輸出轉換后的文本串。示例1
輸入
復制
abababcd ab cd輸出
復制
cdcdcdcd解題報告:
? ? KMP就好了,記錄下來每一個匹配的第一個位置,然后遍歷整個字符串,遇到匹配的位置的時候就輸出替換串,直到遍歷完第一個字符串。
AC代碼:
#include<cstdio> #include<cstring> #define ll long long using namespace std; char s[1000005]; char t[1000005]; char ac[1000005]; int Next[1000005]; int ans[1000005]; int len1,len2,cnt; void getnext() {int j = 0,k = -1;Next[0] = -1;while(j<len2-1) {if(k == -1 || t[j] == t[k]) {j++,k++;Next[j] = k;} else k = Next[k];} } int kmp() {int i=0,j=0;while(i < len1) {if(j == -1 || s[i] == t[j]) {i++,j++;} else {j=Next[j];}if(j >= len2) {ans[++cnt] = i-len2;j=0;}}return cnt;} int main() {scanf("%s",s);scanf("%s",t);scanf("%s",ac);len1 = strlen(s);len2 = strlen(t);getnext();kmp();//printf("%d\n",kmp());int cur = 1;int i = 0;//cout << "ans**" << ans[1]<<endl;while(1) {if(i >= len1) break;if(cur <= cnt) {while(i < ans[cur]) {printf("%c",s[i]);i++;}cur++;i += len2;printf("%s",ac);}else {printf("%c",s[i]),i++;} }return 0; }題干:
鏈接:https://ac.nowcoder.com/acm/contest/372/D
來源:牛客網
?
可能很多人要吐槽為什么標題不是“救救blabla”了。
怪人PM6喜歡數糖紙,不同的糖紙有不同的顏色,一共有 N 張糖紙,第 i 張糖紙顏色為 Ci ,它們的位置都是固定的。PM6喜歡五彩繽紛的糖紙,所以他不希望有重復的顏色。他有一次機會,可以收集任意一段連續區間內的糖紙。求出PM6最多能收集多少張糖紙。
輸入描述:
第一行一個正整數 N ,表示共有 N 張糖紙。 第二行共有 N 個正整數,第 i 個正整數表示第 i 張糖紙的顏色 Ci 對于20%的數據:1<=N<=100 對于40%的數據:1<=N<=1000 對于100%的數據:1<=N<=1e6,0<=Ci<=1e9輸出描述:
一個整數表示PM6最多能收集多少張糖紙。示例1
輸入
復制
5 1 2 2 3 4輸出
復制
3說明
PM6可以收集第3到第5張的糖紙,共有三張。解題報告:
? ? ?尺取法。
AC代碼:(每次固定右邊界,來移動左邊界)
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; #define maxn 1000000 int a[maxn+5]; bool b[1000000005]; int main() {int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);int l=0,ans=1;for(int i=1;i<=n;i++){while(b[a[i]])b[a[++l]]=false;b[a[i]]=true;ans=max(ans,i-l);}printf("%d\n",ans);return 0; }AC代碼2:(固定左邊界看可以到達的右邊界)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e6 + 5; const int FFF = 5e7 + 6; int mp[MAX]; int cnt,a[MAX]; bool vis[FFF]; int HH(int x) {return (1LL*13531*x)%(FFF-100); } int main() {int n;cin>>n;for(int i = 1; i<=n; i++) scanf("%d",&a[i]),mp[i] = HH(a[i]);int l = 1,r = 1,ans = 0;while(l<=r && l <= n) {while(vis[mp[r]] == 0 && r <= n) {vis[mp[r]] = 1,r++;}ans = max(ans,r-l);vis[mp[l]] = 0;l++;}printf("%d\n",ans);return 0 ;}這個實現方法很多,可以Hash可以直接開1e9的數組可以unordered_map,可以用二分來離散化(但是離散化完了要重新記錄到一個數組中,這樣使用的時候是O1的,不能每次使用都從重新計算,因為常數有點扛不住、、)
并且Hash的時候注意不能用rand(),不然可能本來相同的值可能就會被映射到不同地方去了。
這樣寫顯然錯誤:(越界了)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e6 + 5; const int FFF = 5e7 + 6; int mp[MAX]; int cnt,a[MAX]; bool vis[FFF]; int HH(int x) {return (1LL*13531*x)%(FFF-1); } int main() {int n;cin>>n;for(int i = 1; i<=n; i++) scanf("%d",&a[i]),mp[a[i]] = HH(a[i]);int l = 1,r = 1,ans = 0;while(l<=r && l <= n) {while(vis[mp[a[r]]] == 0 && r <= n) {vis[mp[a[r]]] = 1,r++;}ans = max(ans,r-l);vis[mp[a[l]]] = 0;l++;}printf("%d\n",ans);return 0 ;}常數很小的unordered_map(400ms)(我寫的就800ms、、)
#include<cstdio> #include<unordered_map> using namespace std;int main() {unordered_map<int,int>pos;int n,x,now=0,ans=1;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&x);now=i-pos[x]>now?now+1:i-pos[x];ans=ans>now?ans:now;pos[x]=i;}printf("%d\n",ans);return 0; }還可以直接取模:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; #define N 1000001 #define P 1651469 int n,a[N],ans=0; bool v[N*2]; int main() {cin>>n;for(int i=1;i<=n;i++) scanf("%d",&a[i]);int l=1,r=1;v[a[1]%P]=1;while(r<n) {if(v[a[r+1]%P]) {while(a[r+1]!=a[l])v[a[l++]%P]=0;l++;}v[a[++r]%P]=1;ans=max(ans,r-l+1);}cout<<ans<<endl; }寫在后面:
? ?紀念第一場ak...雖然題目很水但畢竟是不熟悉的OI賽制。繼續加油!
總結
以上是生活随笔為你收集整理的【牛客OI周赛7-普及组ABCD 非官方题解】暴力,二分,KMP,尺取(STL或Hash)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【蓝桥杯 - 真题】六角幻方(dfs+
- 下一篇: 【ZOJ - 3946】Highway