9.10 AHSOFNU校內模擬
9.10完整的在AHSOFNU考了一場模擬賽
以下記錄了本次考試的題目(由於mhm想當然的以為是跳石子而沒有sort就打掛惹T-T)
本次考試被出題人判定為普及-(???)
//以下題目中有貼std代碼,等A後修正為自己代碼
——————————————————————分割線——————————————————————————————————————
T1:
CCT
最近學校又發了n本五三題霸,BBS看到後十分高興。但是,當他把五三拿到手後才發現,他已經刷過這些書了!他又認真地看了一會兒,發現新發的這些五三是2017版的,而他刷的是2016版的。現在他想找出所有他沒有刷過的題來刷。每本五三都有m道題,並且它的特征(即它和去年版本的五三的差距)可以用一個m位二進制數來代表,二進制位上的1代表該題不同,0代表該題相同。比如4(100)就代表題目3和去年的有不同、5(101)就代表題目1和題目3和去年的有不同。而BBS熱衷於給自己找麻煩,他要選擇連續一段的幾本五三一起刷,並且要求,所有選擇的五三的特征中的所有k位中每一位出現1的次數都相同。他又想去刷最多的書,請你告訴他,他最多能刷多少本書?
輸入格式:
第一行為兩個整數 n、m,接下來的n行為 n 個整數,表示每本五三的特征。
輸出格式:
一個整數,表示BBS最多能刷幾本書。
樣例輸入 |
樣例輸出 |
7 3 7 6 7 2 1 4 2 |
4 |
樣例解釋:
這7本五三的特征分別為111,110,111,010,001,100,010。選擇第3本至第6本五三,這些五三的特征中每一位都出現了2次1。當然,選擇第4本到第6本也是可以的,這些五三的特征中每一位都出現了1次1。只是這樣子BBS刷的書的數量就少了,他就會不高興。
數據範圍:
對於 100%的數據:1<=n<=100000,1<=k<=30。
solution://不會打(%%%)
CCT:
對於一個特征 a1a2a3...am,我們用(a1-a1)(a2-a1)(a3-a1)...(am-a1)來表示它,然後再做對每一 位前綴和(s1-s1)(s2-s1)(s3-s1)...(sm-s1)。易發現,當兩個位置 i、j 前綴和相同時,i+1 到 j 或 i 到 j-1 即是一種可行的選法。用個 set 記住每個前綴和最早出現的位置,對每個位置在 set 中查 詢並更新答案即可。
1 //這是ditoly的代碼 等我A了就更新自己的代碼 2 #include <cstdio> 3 #include <set> 4 5 int k; 6 struct sth 7 { 8 int num; 9 int dif[30]; 10 bool operator <(const sth &b)const 11 { 12 int i; 13 for(i=1;i<k;i++) 14 { 15 if(dif[i]!=b.dif[i]) return dif[i]<b.dif[i]; 16 } 17 return false; 18 } 19 }t; 20 std::set<sth> s; 21 std::set<sth>::iterator it; 22 int n,x,ans; 23 int sum[100001][31]; 24 25 int max(int a,int b) 26 { 27 return a>b?a:b; 28 } 29 30 int main() 31 { 32 freopen("cct.in","r",stdin); 33 freopen("cct.out","w",stdout); 34 scanf("%d%d",&n,&k); 35 for(int i=1;i<=n;i++) 36 { 37 scanf("%d",&x); 38 for(int j=1;j<=k;j++) 39 { 40 sum[i][j]=sum[i-1][j]; 41 if(x&(1<<(j-1))) sum[i][j]++; 42 } 43 } 44 ans=0; 45 t.num=0; 46 for(int i=1;i<k;i++) t.dif[i]=0; 47 s.insert(t); 48 for(int i=1;i<=n;i++) 49 { 50 t.num=i; 51 for(int j=1;j<k;j++) t.dif[j]=sum[i][j]-sum[i][j+1]; 52 it=s.find(t); 53 if(it==s.end()) s.insert(t); 54 else ans=max(ans,i-(*it).num); 55 } 56 printf("%d",ans); 57 return 0; 58 }
T2:
MHM
LGL今天一共要上n節課,這n節課由0標號至n。由於過度勞累,除了第0節課和第n節課,LGL還打算睡上m節課,所以他做了一個睡覺計劃表。通過小道消息,LGL得知WQ今天會在學校中檢查,所以他想少睡k節課。但是由於某些原因,他又想使相鄰的兩節睡覺的課之間上的課數量的最小值最大。由於他很困,所以他請你來幫他計算這個值。
輸入格式:
第一行為三個整數 n、m、k,接下來的m行為m個整數ai,表示睡覺計劃表中LGL想要睡覺的課。
輸出格式:
一個整數,表示題目所求的值。
樣例輸入 |
樣例輸出 |
25 5 2 14 11 17 2 21 |
3 |
樣例解釋:
選擇第2節和第14節不睡覺,這樣子相鄰的兩節睡覺的課之間上的課數量的最小值為3,即第17節和第21節之間和第21節到第25節之間。沒有答案更大的刪除方案。
數據範圍:
對於100%的數據:1<=n<=109,1<=k<=m<=50000,0<ai<n。
solution:
跳石子原題,連樣例都一樣的(然而我還是打掛了...)
二分答案判定即可,輸入數據要sort一下,如果copy跳石子的代碼記得sort後的Binsearch()-1...
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 int a[50001],l,n,m; 6 int find(int l){ 7 int sum=0,lesson=0; 8 lesson=m; 9 for(int i=0;i<=n;i++){ 10 sum+=a[i]; 11 if(sum<l) lesson--; 12 else sum=0; 13 if(lesson<0) return 0; 14 } 15 return 1; 16 } 17 int BinSearch(){ 18 int left=0,right=l; 19 int mid; 20 while(left<=right){ 21 mid=(left+right)/2; 22 if(find(mid)){ 23 if(mid+1<=right&&find(mid+1)) left=mid+1; 24 else return mid; 25 } 26 else right=mid-1; 27 } 28 return 0; 29 } 30 int main(){ 31 freopen("mhm.in","r",stdin); 32 freopen("mhm.out","w",stdout); 33 int x=0; 34 cin>>l>>n>>m; 35 for(int i=1;i<=n;i++) cin>>a[i]; 36 a[0]=0; 37 a[n+1]=l; 38 sort(a,a+n+1); 39 for(int i=0;i<=n;i++) a[i]=a[i+1]-a[i]; 40 x=BinSearch()-1; 41 cout<<x<<endl; 42 return 0; 43 }
T3:
AAFA
YYH有n道題要做。每一道題都有一個截止日期t,只要在該日期之前做完,他的父親LRB就會獎勵他w元錢。令人驚訝的是,每一道題他都只需要1秒來做。請問他最多能從父親那裏拿到多少錢?
輸入格式:
第一行為一個整數 n,接下來的n行每一行都有兩個數ti和wi,分別表示第i題的截止日期和獎勵。
輸出格式:
一個整數,表示YYH的最大獲利。
樣例輸入 |
樣例輸出 |
3 2 10 1 5 1 7 |
17 |
樣例解釋:
第1秒做第3道題,第2秒做第1道題。
數據範圍:
對於 100%的數據:1<=n、ti 、wi <=100000。
solution:
按截止時間排序從頭往後選。選到第 i 個時,若已選擇的題目數量小於 ti,則該時間選 擇它一定更優;若已選擇的數量等於 ti,則比較第 i 題的收益和已選擇的題目中的最小收益, 在酌情選擇。已選擇的題目用優先隊列維護。
1 //依舊是ditoly的代碼 2 #include<iostream> 3 #include<cstdio> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 priority_queue<int> q; 8 int n;long long ans=0ll; 9 struct xxx{ 10 int t,w; 11 }f[100100]; 12 bool cmp(xxx a,xxx b){return a.t>b.t;} 13 int main() 14 { 15 freopen("aafa.in","r",stdin);freopen("aafa.out","w",stdout); 16 scanf("%d",&n);int y=1; 17 for(int i=1;i<=n;i++)scanf("%d%d",&f[i].t,&f[i].w); 18 sort(f+1,f+n+1,cmp); 19 for(int i=100000;i>=1;i--) 20 { 21 while(i==f[y].t){q.push(f[y].w);y++;} 22 if(!q.empty()){ans+=(long long)q.top();q.pop();} 23 } 24 cout<<ans; 25 return 0; 26 }
T4:
ZZI
YYH拿到了父親給的錢欣喜若狂,把這些錢拿來造了n棟房子。現在他要給這些房子通電。他有兩種方法:第一種是在房間裏搭核電發電機發電,對於不同的房子,他需要花不同的代價Vi;,第二種是將有電的房子i的電通過電線通到沒電的房子j中,這樣子他需要花的代價為aij。他現在請你幫他算出他最少要花多少錢才能讓所有的房子通上電。
輸入格式:
第一行為一個整數 n。接下來的n行為 n 個整數vi,再接下來的n行每行n個數,第i行第j列的數表示aij。
輸出格式:
一個整數,表示最小代價。
樣例輸入 |
樣例輸出 |
4 4 4 3 |
9 |
樣例解釋:
在第4棟房子造核電發電機,再將其他三棟房子通過電線連向它。
數據範圍:
對於 100%的數據:1<=n<=300,1<=vi,aij<=100000,保證aii=0,aij=aji。
solution:
應該是一個裸的最小生成樹。要註意可能建核電站比連邊代價小。
所以可以把建站作為一個新的點加入,直接跑最小生成樹。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int Max_v=305; 5 const int INF=0x7fffffff; 6 int cost[Max_v][Max_v]; 7 int mincost[Max_v]; 8 bool used[Max_v]; 9 int V; 10 int prim(){ 11 fill(mincost,mincost+V,INF); 12 fill(used,used+V,false); 13 mincost[0]=0; 14 int res=0; 15 while(true){ 16 int v=-1; 17 for(int u=0;u<V;u++){ 18 if(!used[u]&&(v==-1||mincost[u]<mincost[v])) v=u; 19 } 20 if(v==-1) break; 21 used[v]=true; 22 res+=mincost[v]; 23 for(int u=0;u<V;u++) 24 if (cost[v][u])mincost[u]=min(mincost[u],cost[v][u]); 25 } 26 return res; 27 } 28 int main(){ 29 freopen("zzi.in","r",stdin); 30 freopen("zzi.out","w",stdout); 31 scanf("%d",&V); 32 for(int i=0;i<V;i++) 33 scanf("%d",&cost[i][V]),cost[V][i]=cost[i][V]; 34 cost[V][V]=0; 35 for(int i=0;i<V;i++) 36 for(int j=0;j<V;j++) 37 scanf("%d",&cost[i][j]); 38 V++; 39 cout<<prim(); 40 return 0; 41 }
9.10 AHSOFNU校內模擬