第四章:枚举 模拟 排序习题 【完结】
基本熟練掌握。
目錄
- 1210. 連號區(qū)間數(shù) 【枚舉 】
- 1236. 遞增三元組 【枚舉 / 前綴和 / hush定址法】
- 1245. 特別數(shù)的和 【簡單】
- 1204. 錯誤票據(jù) 【簡單】
- 466. 回文日期 【枚舉】
- 787. 歸并排序 【板子題】
- 1219. 移動距離 【找規(guī)律】
- 1229. 日期問題 【枚舉】
- 1231. 航班時間 【模擬】
- 788. 逆序?qū)Φ臄?shù)量 【板子題】
- 1241. 外賣店優(yōu)先級 【大模擬題】
1210. 連號區(qū)間數(shù) 【枚舉 】
題目詳解
1236. 遞增三元組 【枚舉 / 前綴和 / hush定址法】
https://www.acwing.com/problem/content/1238/
思路: 找中間的數(shù)組B 因為選B的話 剩下的A和C之間就沒有影響了。
對于數(shù)組中的每一個B 的元素 我們只要統(tǒng)計A中小于它的數(shù)值有多少個,C中大于它的數(shù)值有多少個。
兩者相乘,并求其和就為總的個數(shù)。
以A來說: 首先用一個數(shù)組來統(tǒng)計各個數(shù)據(jù)的個數(shù)。
再用一個數(shù)組 求其前綴和。這樣就可以得到小于B的數(shù)組的元素個數(shù)。
y總的思路就是:
先說A(C和A的方法一樣,就不贅述),用一個數(shù)組來統(tǒng)計各個數(shù)字出現(xiàn)的次數(shù)。
就是定址法。 再用一個前綴和,來統(tǒng)計每個小于等當前位置的所有的數(shù)的出現(xiàn)次數(shù)。
最后通過B的數(shù)的值來找到對應(yīng)的前綴和,即找到了小于B的數(shù)出現(xiàn)的次數(shù)。
1.第一個問題: 為啥要統(tǒng)一加一?
統(tǒng)一加1的目的是為了防止數(shù)組越界。
2.第二個問題: 為啥前綴和的for 是從1~N
其實1~N指的是數(shù)據(jù)范圍內(nèi) 的前綴和。不要以為是 1~n,這只是我們數(shù)的個數(shù),并不是數(shù)值的大小
1245. 特別數(shù)的和 【簡單】
#include<bits/stdc++.h> using namespace std; int sum,n; bool judge(int x) {while(x){int t=x%10;if(t==2||t==0||t==1||t==9) return true;x/=10;}return false; } int main(void) {cin>>n;for(int i=1;i<=n;i++) if(judge(i)) sum+=i;cout<<sum;return 0; }1204. 錯誤票據(jù) 【簡單】
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int n,a[N],k,cnt[N]; int main(void) {cin>>n;while(cin>>a[k++]);sort(a,a+k);int l,r;for(int i=0;i<k;i++){if(i&&a[i]-a[i-1]>1) l=a[i]-1;cnt[a[i]]++;if(cnt[a[i]]>1) r=a[i];}cout<<l<<" "<<r;return 0; }466. 回文日期 【枚舉】
https://www.acwing.com/problem/content/468/
暴力方法: 超時了
巧妙的思路: 我們只要枚舉前4位,組成回文數(shù)字,看是不是合法的日期就可以了。
#include<iostream> using namespace std;int m[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};bool judge(int n) {if(n%400==0||n%4==0&&n%100!=0) return true;else return false; }int data1,data2; int ans;bool check(int n) {if(judge(n/10000)) m[2]=29;int month=n%10000/100;int day=n%100;if(month==0||month>=13) return false;if(day==0||day>m[month]) return false;return true; } int main(void) {cin>>data1>>data2;for(int i=1000;i<=10000;i++){int temp=i;int x=i;for(int j=0;j<4;j++)//回文數(shù)字{temp=temp*10+x%10;x/=10;}if(temp>=data1&&temp<=data2&&check(temp)){ans++;}}cout<<ans<<endl;return 0; } #include<bits/stdc++.h> using namespace std; int l,r,ans; bool flag; int m[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; bool judge(int x) {if( (x%400==0) || (x%4==0&&x%100!=0)) return true;else return false; } bool check(int x) {string s=to_string(x);string temp=s;reverse(temp.begin(),temp.end());s+=temp;int year=stoi(s.substr(0,4));if(year<1000) return false;int month=stoi(s.substr(4,2));if(month==0||month>=13) return false;if(month==2&&judge(year)) m[2]=29;int day=stoi(s.substr(6,2));if(day<=0||day>m[month]) return false;x=stoi(s);if(x>=l&&x<=r) return true;else return false;m[2]=28; } int main(void) {cin>>l>>r;for(int i=1000;i<=9999;i++){if(check(i)) ans++;if(flag) break;}cout<<ans;return 0; }787. 歸并排序 【板子題】
https://www.acwing.com/problem/content/789/
1219. 移動距離 【找規(guī)律】
思路: 找下標和對應(yīng)數(shù)的規(guī)律。
巧妙的一點在于: 整體減1。這樣就少了很多的特判。
例如: 如果不整體減1 , 1的行號=1/6=0 但是 6的行號=6/6=1 這顯然不行,我們還得進一步的判斷。
但是如果整體減1后 1-1=0/6=0 6-1=5/6=0 這樣就少了特判。十分的方便。
一個字: 秒!
精簡版:
#include<iostream> #include<string> #include<cmath> using namespace std; int main(void) {int w,m,n; cin>>w>>m>>n;int x1,y1,x2,y2;m--,n--;x1=m/w;x2=n/w;y1=m%w;y2=n%w;if(x1&1) y1=w-1-m%w;//行數(shù)是奇數(shù)if(x2&1) y2=w-1-n%w;//行數(shù)是奇數(shù) cout<<abs(x1-x2)+abs(y1-y2)<<endl;return 0; } #include<bits/stdc++.h> using namespace std; int w,m,n; int x,y,xx,yy; int main(void) {cin>>w>>m>>n;x=(m-1)/w;xx=(n-1)/w;if(x%2==0) y=(m-w*x)%(w+1)-1;else y=w-(m-w*x)%(w+1);if(xx%2==0) yy=(n-w*xx)%(w+1)-1;else yy=w-(n-w*xx)%(w+1);cout<<abs(x-xx)+abs(y-yy);return 0; }1229. 日期問題 【枚舉】
https://www.acwing.com/problem/content/1231/
模擬寫法:
#include<cstring> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; int m[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; bool judge(int year) {if(year%400==0|| (year%4==0&&year%100!=0) ) return true;else return false; } struct date {int year;int month;int day; }d[10]; bool cmp(date a,date b) {if(a.year==b.year){if(a.month==b.month){return a.day<b.day;}return a.month<b.month;}return a.year<b.year; } int main(void) {int x1,x2,x3;scanf("%d/%d/%d",&x1,&x2,&x3);int sum=x1+1900;//x1為年 x2為月 x3為日 int number=0;if(sum>=1960&&sum<=2059){if(judge(sum))m[2]=29; if(x2>=1&&x2<=12){if(x3>=1&&x3<=m[x2]){d[number].year=sum;d[number].month=x2;d[number++].day=x3;}}m[2]=28;}sum=x1+2000;if(sum>=1960&&sum<=2059){if(judge(sum))m[2]=29; if(x2>=1&&x2<=12){if(x3>=1&&x3<=m[x2]){d[number].year=sum;d[number].month=x2;d[number++].day=x3;}}m[2]=28;}int sum2=x3+1900;//x1為月 x2為日 x3為年 if(sum2>=1960&&sum2<=2059){if(judge(sum2))m[2]=29; if(x1>=1&&x1<=12){if(x2>=1&&x2<=m[x1]){d[number].year=sum2;d[number].month=x1;d[number++].day=x2;}}m[2]=28;}sum2=x3+2000;if(sum2>=1960&&sum2<=2059){if(judge(sum2))m[2]=29; if(x1>=1&&x1<=12){if(x2>=1&&x2<=m[x1]){d[number].year=sum2;d[number].month=x1;d[number++].day=x2;}}m[2]=28;}int sum3=x3+1900;//x1為日 x2為月 x3為年 if(sum3>=1960&&sum3<=2059){if(judge(sum3))m[2]=29; if(x2>=1&&x2<=12){if(x1>=1&&x1<=m[x2]){d[number].year=sum3;d[number].month=x2;d[number++].day=x1;}}m[2]=28;}sum3=x3+2000;if(sum3>=1960&&sum3<=2059){if(judge(sum3))m[2]=29; if(x2>=1&&x2<=12){if(x1>=1&&x1<=m[x2]){d[number].year=sum3;d[number].month=x2;d[number++].day=x1;}}m[2]=28;}sort(d,d+number,cmp);printf("%d-%02d-%02d\n",d[0].year,d[0].month,d[0].day);for(int i=1;i<number;i++) {//去重 if( (d[i].year==d[i-1].year) && (d[i].month==d[i-1].month) && (d[i].day==d[i-1].day) )continue;printf("%d-%02d-%02d\n",d[i].year,d[i].month,d[i].day);}return 0; }枚舉寫法: 操作簡單,枚舉所有的日期看是不是,是合法的日期,再看是不是和我們輸入的日期相匹配。
#include<cstdio> #include<iostream> #include<string> using namespace std; int m[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int x1,x2,x3; bool judge(int n) {if(n%400==0|| (n%4==0&&n%100!=0) ) return true;else return false; } bool check(int a,int b,int c) {if(a==x1&&b==x2&&c==x3)return true;return false; } int main(void) {scanf("%d/%d/%d",&x1,&x2,&x3);for(int i=19600101;i<=20591231;i++){int year=i/10000;int month=i%10000/100;int day=i%100;if(judge(year)) m[2]=29;if(month>=1&&month<=12&&day>=1&&day<=m[month])//日期合法 if(check(year%100,month,day)||check(month,day,year%100)||check(day,month,year%100))//匹配 {printf("%d-%02d-%02d\n",year,month,day);}m[2]=28;}return 0; }1231. 航班時間 【模擬】
https://www.acwing.com/problem/content/1233/
公式: 飛行時間=(兩次時間差的和)/2
飛機在飛,由于人為規(guī)定的時區(qū)導(dǎo)致好像時間變慢或者快了(實際上沒有)。這里很像我們高中物理學(xué)的運動學(xué)知識,我們可以假設(shè)一個場景——船在不平靜水面行駛,船從一個點出發(fā)行駛了s路程后返回原點(期間船速不變),然后告訴我們來回整個過程回到原點的時間是t,問船在靜水中行駛s路程需要多長時間。我們可以以水為參考系,那么顯然這個時間為 t/2。
方法一:
#include<cstdio> #include<iostream> #include<string>using namespace std;int get_second(int h,int m,int s)//表示從00:00:00 到當前時間的秒數(shù)和 {return h*3600+m*60+s; }int get_time() {string line;getline(cin,line);if(line.back()!=')') line+="(+0)";int h1,m1,s1,h2,m2,s2,d;sscanf(line.c_str(),"%d:%d:%d %d:%d:%d (+%d)",&h1,&m1,&s1,&h2,&m2,&s2,&d);return get_second(h2,m2,s2)-get_second(h1,m1,s1)+d*24*3600; }int main(void) {int n; scanf("%d",&n);string line;getline(cin,line);while(n--){int time=(get_time()+get_time())/2;int hour=time/3600,minute=time%3600/60,second=time%60;printf("%02d:%02d:%02d\n",hour,minute,second);}return 0; }方法二:
#include<bits/stdc++.h> using namespace std; int getTime(void) {int h1,m1,s1,h2,m2,s2,d=0;scanf("%d:%d:%d %d:%d:%d (+%d)",&h1,&m1,&s1,&h2,&m2,&s2,&d);int time=d*24*3600+h2*3600+m2*60+s2-(h1*3600+m1*60+s1);return time; } int main() {int t;scanf("%d",&t);for(int i = 0; i < t; i++){int time1=getTime();int time2=getTime();int t=(time1+time2)/2;printf("%02d:%02d:%02d\n", t/3600, t/60%60, t%60);}return 0; } #include<bits/stdc++.h> using namespace std; int n; int get() {string s; getline(cin,s);int a,b,c,aa,bb,cc;sscanf(s.c_str(),"%d:%d:%d %d:%d:%d",&a,&b,&c,&aa,&bb,&cc);int sum=0;if(s.find('+')!=-1){string ss=s.substr(s.find('+')+1,1);aa+=stoi(ss)*24;}sum=aa*3600+bb*60+cc-a*3600-b*60-c;return sum; } int main(void) {cin>>n;string s; getline(cin,s);while(n--){int sum=(get()+get())/2;printf("%02d:%02d:%02d\n",sum/3600,(sum%3600)/60,sum%60);}return 0; }788. 逆序?qū)Φ臄?shù)量 【板子題】
https://www.acwing.com/solution/content/2103/
思路: 就是用到了歸并排序。歸并排序有一個特點就是分割的區(qū)間都是有序的,即遞增的。
#include<cstdio> #include<iostream> #define LL long long using namespace std; const int N=100100; int a[N],temp[N]; int n; LL res; void merge_sort(int q[],int l,int r) {if(l>=r) return;int mid=l+r>>1;merge_sort(q,l,mid),merge_sort(q,mid+1,r);int k=0,i=l,j=mid+1;while(i<=mid&&j<=r) {if(a[i]<=a[j]) temp[k++]=a[i++];else{res+=mid-i+1;//重中之重temp[k++]=a[j++];}}while(i<=mid) temp[k++]=a[i++];while(j<=r) temp[k++]=a[j++];for(i=l,j=0;i<=r;i++,j++) a[i]=temp[j]; } int main(void) {scanf("%d",&n);for(int i=0;i<n;i++) scanf("%d",&a[i]);merge_sort(a,0,n-1); cout<<res;return 0; }為啥 res+=mid-i-1 ? 這是因為:
數(shù)組a中的i ~ mid的數(shù)組是遞增數(shù)組, 觸發(fā)條件是a[i] > a[j],所以i~mid中的數(shù)字都比當前a[j]大,
所以左邊i ~ mid的數(shù)組中有 mid - i + 1個數(shù)比a[j] 大
1241. 外賣店優(yōu)先級 【大模擬題】
#include<bits/stdc++.h> using namespace std; const int N=1e6+10; int n,m,t,ans; map<int,vector<int> >mp; int st[N]; int main(void) {cin>>n>>m>>t;while(m--){int a,b; cin>>a>>b;mp[b].push_back(a);}for(auto i=1;i<=n;i++){sort(mp[i].begin(),mp[i].end());int score=0,index=0;for(int j=0;j<mp[i].size();j++){int cnt=1;int k=j;while( ( (k+1) < mp[i].size() ) && (mp[i][k]==mp[i][k+1]) ) cnt++,k++;score-=(mp[i][j]-index-1);if(score<0) score=0;if(score<=3) st[i]=0;score+=cnt*2;index=mp[i][j];if(score>5) st[i]=1;j=k;}if(index<t) score-=(t-index);if(score<=3) st[i]=0;}for(int i=1;i<=n;i++) ans+=st[i];cout<<ans;return 0; }總結(jié)
以上是生活随笔為你收集整理的第四章:枚举 模拟 排序习题 【完结】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第七章:贪心习题
- 下一篇: dfs解决选或不选问题