转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
自己开的专题,用于集训队暑期集训。题目来源已经给出。
1001
部分背包问题。优先选取性价比高的,将单位价格进行排序,依次选取,直至满足条件。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node{ int j,f; double p; }a[1000]; int n,m; bool cmp(Node n1,Node n2){ return n1.p>n2.p; } int main(){ while(scanf("%d%d",&n,&m)!=EOF&&(n!=-1&&m!=-1)){ for(int i=0;i<m;i++){ scanf("%d%d",&a[i].j,&a[i].f); a[i].p=a[i].j*1.0/a[i].f; } sort(a,a+m,cmp); double ans=0; int tmp=0; for(int i=0;i<m;i++){ if(a[i].f+tmp>=n){ if(a[i].f+tmp==n) ans+=a[i].j; else ans+=a[i].p*(n-tmp); break; } else{ ans+=a[i].j; tmp+=a[i].f; } } printf("%.3f\n",ans); } return 0; }
1002
没有交叉的区间是可以同时进行的。那么需要的次数便是某个点所经过的最大次数。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int t,n,x,y,a[205]; int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); memset(a,0,sizeof(a)); while(n--){ scanf("%d%d",&x,&y); if(x>y) swap(x,y); for(int i=(x+1)/2;i<=(y+1)/2;i++) a[i]++; } int ans=0; for(int i=1;i<=200;i++) ans=max(ans,a[i]); printf("%d\n",ans*10); } return 0; }
1003
贪心思想,先放6*6,格子已经全部放满,然后放5*5,剩下的空间可以用来放1*1,然后放4*4,剩余的空间可以放2*2,然后放1*1,之后放3*3,同理处理完剩余空间,最后考虑2*2,1*1。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int a,b,c,d,e,f; int main(){ int u[4]={0,5,3,1}; while(scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f)&&a+b+c+d+e+f){ int ans=d+e+f+(c+3)/4; int x=d*5+u[c%4]; if(b>=x) ans+=(b-x+8)/9; int y=36*ans-36*f-25*e-16*d-9*c-4*b; if(a>y) ans+=(a-y+35)/36; printf("%d\n",ans); } return 0; }
1004
不错的题目,暴力可解,但是没有意思。可以发现规律
排序之后,对于每一组相邻的差a[pos]-a[pos-1],当i取0-(pos-1)以及j取pos-n时,i和j之间的差值必然包括a[pos]-a[pos-1]。
那么a[pos]-a[pos-1]出现的次数是i*(n-i)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[10000],n; int main(){ while(scanf("%d",&n)!=EOF){ for(int i=0;i<n;i++) scanf("%d",&a[i]); sort(a,a+n); LL ans=0; for(int i=1;i<n;i++) ans+=(LL)(a[i]-a[i-1])*i*(n-i); printf("%I64d\n",ans*2); } return 0; }
1005
按两个关键字从小到大排序,之后遍历。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node{ int l,r; }a[5000]; int n; bool cmp(Node n1,Node n2){ return n1.l!=n2.l?n1.l<n2.l:n1.r<n2.r; } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d%d",&a[i].l,&a[i].r); sort(a,a+n,cmp); bool flag[5000]; memset(flag,false,sizeof(flag)); int ans=0; for(int i=0;i<n;i++){ if(flag[i]) continue; int L=a[i].l,R=a[i].r; ans++; for(int j=i;j<n;j++) if(a[j].l>=L&&a[j].r>=R&&flag[j]==false){ L=a[j].l; R=a[j].r; flag[j]=true; } } printf("%d\n",ans); } return 0; }
1006
每个人手中有m张牌,有n个人,牌上的数字分别为1-n*m,互不相等。
赢的最少情况肯定是自己出大的,别人有大的,肯定压,否则别人出最小的。
每次选取最大的牌出,如果别人有大牌,则输,否则别人出最小的。不需要模拟,从大到小遍历一次。如果某张牌我有,说明我可以赢,+1,如果没有,说明别人可以比我大一次,-1。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[1005],n,m,k,cas=0; bool flag[1005]; int main(){ while(scanf("%d%d",&n,&m)!=EOF&&n+m){ memset(flag,false,sizeof(flag)); for(int i=0;i<m;i++){ scanf("%d",&k); flag[k]=true; } int ans=0,tmp=0; for(int i=n*m;i>0;i--) if(flag[i]){ tmp++; ans=max(ans,tmp); } else tmp--; printf("Case %d: %d\n",++cas,ans); } return 0; }
1007
离散化所有带宽。
枚举带宽,作为最小的带宽。然后在每一组选取满足最小带宽,而且价格最低的。
所以对于每一组按价格递增排序。优先考虑价格低的。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node{ int b,p; }a[400][400]; int t,m[400],B[160000],cnt,n; bool cmp(Node n1,Node n2){ return n1.p<n2.p; } int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); cnt=0; for(int i=0;i<n;i++){ scanf("%d",&m[i]); for(int j=0;j<m[i];j++){ scanf("%d%d",&a[i][j].b,&a[i][j].p); B[cnt++]=a[i][j].b; } sort(a[i],a[i]+m[i],cmp); } sort(B,B+cnt); int CNT=1; for(int i=1;i<cnt;i++) if(B[i]!=B[CNT-1]) B[CNT++]=B[i]; double ans=0; for(int k=0;k<CNT;k++){ int ptmp=0,flag=1; for(int i=0;i<n;i++){ int j; for(j=0;j<m[i];j++) if(a[i][j].b>=B[k]) break; if(j==m[i]){ flag=0; break; } ptmp+=a[i][j].p; } if(flag) ans=max(ans,B[k]*1.0/ptmp); } printf("%.3f\n",ans); } return 0; }
1008
骑车去上学。时间为负的车子不用考虑,因为要不是追不上,要么追上也不是最快的。然后求出每辆车的所需时间,求出最小值。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node { int v,t,need; }a[10000]; int n; int main(){ while(scanf("%d",&n)!=EOF&&n){ for(int i=0;i<n;i++) scanf("%d%d",&a[i].v,&a[i].t); for(int i=0;i<n;i++){ if(a[i].t<0) a[i].need=inf; else{ a[i].need=(int)((4500*3.6)/a[i].v+a[i].t); if((int)(4500*3.6)%a[i].v) a[i].need++; } } int ans=a[0].need; for(int i=1;i<n;i++) ans=min(ans,a[i].need); printf("%d\n",ans); } return 0; }
1009
同样的根据价值递减排序,先满足价值高的先做,日期尽可能靠后。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node{ int d,p; }a[1000]; bool cmp(Node n1,Node n2){ return n1.p>n2.p; } int n,t; int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i].d); for(int i=0;i<n;i++) scanf("%d",&a[i].p); sort(a,a+n,cmp); int ans=0; bool flag[10000]; memset(flag,false,sizeof(flag)); for(int i=0;i<n;i++){ int j; for(j=a[i].d;j>=1;j--) if(flag[j]==false){ flag[j]=true; break; } if(j==0) ans+=a[i].p; } printf("%d\n",ans); } return 0; }
1010
按结束时间排序,然后依次遍历。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node{ int l,r; }a[100]; int n; bool cmp(Node n1,Node n2){ return n1.r!=n2.r?n1.r<n2.r:n1.l>n2.l; } int main(){ while(scanf("%d",&n)!=EOF&&n){ for(int i=0;i<n;i++) scanf("%d%d",&a[i].l,&a[i].r); sort(a,a+n,cmp); int ans=1,k=0; for(int i=1;i<n;i++) if(a[i].l>=a[k].r){ ans++; k=i; } printf("%d\n",ans); } return 0; }
1011
贪心,每次优先选取价值高的,而且尽量时间靠后的。用flag数组标记,某天是否已经被利用,如果已经被利用,则往前遍历。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node{ int p,d; }a[10000]; bool cmp(Node n1,Node n2){ return n1.p>n2.p; } int n; int main(){ while(scanf("%d",&n)!=EOF){ for(int i=0;i<n;i++) scanf("%d%d",&a[i].p,&a[i].d); sort(a,a+n,cmp); int ans=0; bool flag[10005]; memset(flag,false,sizeof(flag)); for(int i=0;i<n;i++) for(int t=a[i].d;t>0;t--) if(flag[t]==false){ ans+=a[i].p; flag[t]=true; break; } printf("%d\n",ans); } return 0; }
1012
对于每一个岛,存在一个区间,区间内任意位置建的雷达都能覆盖岛屿。这样就形成若干个区间。对于每一个区间从左到右遍历,尽可能选取最右端点,这样就能满足最多的区间。可以处理掉子区间。或者在遍历的时候遇到子区间,就尽可能取子区间的右端点。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node{ double l,r; }a[1000]; int n,d; bool cmp(Node n1,Node n2){ return n1.l<n2.l; } int main(){ int cas=0; while(scanf("%d%d",&n,&d)!=EOF&&n+d){ bool flag=true; for(int i=0;i<n;i++){ int x,y; scanf("%d%d",&x,&y); if(abs(y)>d) flag=false; if(!flag) continue; a[i].l=x-sqrt((double)d*d-y*y); a[i].r=x+sqrt((double)d*d-y*y); } if(!flag){ printf("Case %d: -1\n",++cas); continue; } sort(a,a+n,cmp); int ans=1; double pos=a[0].r; for(int i=1;i<n;i++) if(a[i].l>pos){ pos=a[i].r; ans++; } else if(a[i].r<pos) pos=a[i].r; printf("Case %d: %d\n",++cas,ans); } return 0; }
1013
对于每一个池塘,从左到右依次放木板。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,d; struct Node{ int l,r; }a[10000]; bool cmp(Node n1,Node n2){ return n1.l<n2.l; } int main(){ while(scanf("%d%d",&n,&d)!=EOF){ for(int i=0;i<n;i++) scanf("%d%d",&a[i].l,&a[i].r); sort(a,a+n,cmp); int ans=0,pos=-inf; for(int i=0;i<n;i++){ if(a[i].l>pos){ ans+=(a[i].r-a[i].l+d-1)/d; pos=(a[i].r-a[i].l+d-1)/d*d+a[i].l; } else if(a[i].r>pos){ ans+=(a[i].r-pos+d-1)/d; pos=(a[i].r-pos+d-1)/d*d+pos; } } printf("%d\n",ans); } return 0; }
1014
黑书上的例题。首先枚举走过的湖泊数X,则从1走到X,路上花的时间可以算出。每一次选一个鱼最多的湖泊钓鱼,对于每个湖泊来说,由于 在任何时候鱼的数目只和在这个湖泊里钓鱼的次数有关,和总次数无关。所以这样是最优的。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int main() { int n,h,f[30],d[30],t[30],Case=0; while(scanf("%d",&n),n>0) { if(Case!=0) printf("\n"); Case++; scanf("%d",&h); h=h*60; for(int i=1;i<=n;i++) scanf("%d",&f[i]); for(int i=1;i<=n;i++) scanf("%d",&d[i]); t[1]=0; for(int i=1;i<=n-1;i++) { int a; scanf("%d",&a); t[i+1]=t[i]+a*5; } int fish=0; int f_temp[30]; int spe[30]; int spe_temp[30]; int tt; for(int i=1;i<=n;i++) spe[i]=-1; for(int i=1;i<=n;i++) { int sum=0; tt=h-t[i]; for(int j=1;j<=n;j++) f_temp[j]=f[j]; memset(spe_temp,0,sizeof(spe_temp)); while(tt>=5) { int mmax=0,maxj=-1; for(int j=1;j<=i;j++) { if(f_temp[j]>mmax) { mmax=f_temp[j]; maxj=j; } } if(maxj==-1) break; tt=tt-5; spe_temp[maxj]++; sum+=f_temp[maxj]; f_temp[maxj]=f_temp[maxj]-d[maxj]; } if(sum>fish) { fish=sum; for(int j=1;j<=n;j++) spe[j]=spe_temp[j]; spe[1]+=tt/5; } else if(sum==fish) { bool flag=false; for(int j=1;j<=n;j++) if(spe[j]<spe_temp[j]) { flag=true; break; } else if(spe[j]>spe_temp[j]) break; if(flag) { fish=sum; for(int j=1;j<=n;j++) spe[j]=spe_temp[j]; spe[1]+=tt/5; } } } for(int i=1;i<n;i++) printf("%d, ",spe[i]*5); printf("%d\nNumber of fish expected: %d\n",spe[n]*5,fish); } return 0; }
1015
经典贪心,详见http://blog.csdn.net/acm_cxlove/article/details/7720218
1016
肯定所有的物品都要买,依次选取价值高的物品,这样打折的物品价格也高
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int t,n,a[20000]; int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); sort(a,a+n); int ans=0; for(int i=n-3;i>=0;i-=3) ans+=a[i]; printf("%d\n",ans); } return 0; }