9.10完整的在AHSOFNU考了一场模拟赛
以下记录了本次考试的题目(由于mhm想当然的以为是跳石子而没有sort就打挂惹T-T)
本次考试被出题人判定为普及-(???)
//以下题目中有贴std代码,等A后修正为自己代码
——————————————————————分割线——————————————————————————————————————
T1:
最近学校又发了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:
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:
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:
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 }
原文:http://www.cnblogs.com/drizzly/p/7502927.html