bzoj usaco 金组水题题解(2.5)
bzoj 2197: [Usaco2011 Mar]Tree Decoration
树形dp。。f[i]表示处理完以i为根的子树的最小时间。
因为一个点上可以挂无数个,所以在点i上挂东西的单位花费就是i所在子树里的最小单位花费。。
所以每次求f[i]只要使子树里的数量都满足要求就好了。。i的祖先还要更多的话随时可以选某个节点多挂一些。。
f[i]=sum{f[j]}+mincost[i]*max(need[i]-sum{need[j]},0)。。(j是i的儿子,mincost[i]表示子树i里的最小花费,need[i]表示i这颗子树需要的最少数量)
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #define ll long long
- using namespace std;
- const int maxn=;
- struct zs{
- int too,pre;
- }e[maxn];
- int last[maxn],mn[maxn],tot;
- int i,j,k,n,m,a;
- ll f[maxn],need[maxn];
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- void dfs(int x){
- int i,to;ll sum=;
- for(i=last[x],to=e[i].too;i;mn[x]=mn[x]>mn[to]?mn[to]:mn[x],sum+=need[to],f[x]+=f[to],i=e[i].pre,to=e[i].too)dfs(to);
- if(sum>=need[x])need[x]=sum;else f[x]+=(need[x]-sum)*(ll)mn[x];
- }
- int main(){
- n=read();for(rx=getchar();rx!='-';rx=getchar());rx=getchar();
- need[]=read();mn[]=read();
- for(i=;i<=n;i++)a=read(),e[i].pre=last[a],last[a]=e[i].too=i,need[i]=read(),mn[i]=read();
- dfs();
- printf("%lld\n",f[]);
- return ;
- }
bzoj 2097: [Usaco2010 Dec]Exercise 奶牛健美操
没思路跑去看题解系列。。。二分答案。。
假设二分出来的答案是mid,那么对于每颗子树,设根节点为i,那么删边后子树的直径不能超过mid。
子树内的路径分两种情况,一种是经过i的,另一种是不经过i的。不经过i的显然可以递归i的子节点去删边,删完边后,如果i的任意两个儿子可以通过i凑成一条超过mid的路径的话,就贪心地把i和对长度贡献较大的孩子之间的连边删掉。
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- #include<cstdlib>
- using namespace std;
- const int maxn=;
- struct child{
- int x,len;
- };
- struct zs{
- int too,pre;
- }e1[maxn<<],e[maxn];
- int tot,t1;
- int l1[maxn],last[maxn],mxdep[maxn];
- int i,j,mx,n,m,cnum,a,b,l,r,mid;
- child ch[maxn];
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- inline void ins1(int a,int b){
- e1[++t1].too=b;e1[t1].pre=l1[a];l1[a]=t1;
- e1[++t1].too=a;e1[t1].pre=l1[b];l1[b]=t1;
- }
- inline void insert(int a,int b){e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;}
- void dfs1(int x,int fa){for(int i=l1[x];i;i=e1[i].pre)if(e1[i].too!=fa)insert(x,e1[i].too),dfs1(e1[i].too,x);}
- bool cmp(child a,child b){return a.len<b.len;}
- int dfs(int x,int val){
- int i,ans=,to;
- for(i=last[x];i&&ans<=mx;i=e[i].pre)
- ans+=dfs(e[i].too,val);
- if(ans>mx)return mx+;
- cnum=;
- for(i=last[x],to=e[i].too;i;i=e[i].pre,to=e[i].too)
- ch[++cnum].x=to,ch[cnum].len=mxdep[to]+;
- sort(ch+,ch++cnum,cmp);ch[].len=;
- for(i=cnum;i&&ch[i].len+ch[i-].len>val;i--)ans++;
- mxdep[x]=ch[i].len;
- return ans;
- }
- int main(){
- srand();
- n=read();mx=read();if(mx==n-){puts("");return ;}if(mx==n-){puts("");return ;}
- for(i=;i<n;i++)a=read(),b=read(),ins1(a,b);
- int rt=rand()%n+;
- dfs1(rt,);
- l=;r=n-;
- while(l<r){
- mid=(l+r)>>;
- if(dfs(rt,mid)<=mx)r=mid;else l=mid+;
- }
- printf("%d\n",l);
- return ;
- }
bzoj 1694: [Usaco2007 Demo]Grazing on the Run
又是英文题面+双倍经验= =同bzoj1742。。。。双倍经验==>双倍#1。。233
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<cstdlib>
- #include<algorithm>
- using namespace std;
- const int maxn=;
- int f[maxn][];
- int len,s,mxj,n;
- int a[maxn],b[maxn];
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- int main(){
- int i,j,mxj,tmp;
- n=read();s=read();
- for(i=;i<=n;i++)a[i]=read();sort(a+,a++n);
- for(i=;i<=n;b[i]=a[i+]-a[i],i++)f[i][]=f[i][]=abs(s-a[i])*n;
- for(i=,mxj=n-;i<n;mxj--,i++)for(j=;j<=mxj;j++)
- tmp=f[j][],f[j][]=min(f[j+][]+mxj*b[j],f[j+][]+mxj*(a[j+i]-a[j])),
- f[j][]=min(tmp+mxj*(a[j+i]-a[j]),f[j][]+mxj*b[j+i-]);
- printf("%d\n",min(f[][],f[][]));
- return ;
- }
bzoj 2501: [usaco2010 Oct]Soda Machine
区间加后查询最大值。。写了离散化后二分。。其实离散化姿势正确的话是不用二分找出区间左右端点位置的TAT。
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int maxn=;
- int mp[maxn<<],l[maxn],r[maxn],sum[maxn<<];
- int i,j,ans,n,size,nowsum;
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- inline int get(int x){
- int l=,r=size,mid;
- while(l<r){
- mid=(l+r+)>>;
- if(mp[mid]<=x)l=mid;else r=mid-;
- }return l;
- }
- int main(){
- n=read();
- for(i=;i<=n;i++)l[i]=mp[i]=read(),r[i]=mp[i+n]=read();
- sort(mp+,mp++n*);size=;n<<=;
- for(i=;i<=n;i++)if(mp[i]!=mp[i-])mp[++size]=mp[i];n>>=;
- for(i=;i<=n;i++)sum[get(l[i])]++,sum[get(r[i])+]--;
- for(i=;i<=size;i++){
- nowsum+=sum[i];
- if(nowsum>ans)ans=nowsum;
- }
- printf("%d\n",ans);
- return ;
- }
bzoj 1915: [Usaco2010 Open]奶牛的跳格子游戏
dp+单调队列优化 http://www.cnblogs.com/czllgzmzl/p/5084120.html
bzoj 1729: [Usaco2005 dec]Cow Patterns 牛的模式匹配
正解似乎是kmp。。。具体见网上题解
然而我偷懒写了hash= =。。。结果卧槽又长又慢
如何判断网上题解挺详细的。。。然而事实告诉我们其实并不用那么严格。。选几个类似(并好维护些)的指标(比方说轮廓啊什么的)。。符合的话就再随机几个点确定一下是不是真的全都符合= =。。。。这样大概就可以了吧
真相是看网上题解时几个字看错TAT。。结果拍了半天。。最后直接再rand几个数判断= =。。写了4个hashTAT
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- #include<ctime>
- #include<cstdlib>
- #define ll long long
- #define ull unsigned int
- using namespace std;
- const int maxn=;
- const int maxk=;
- int sum[],num[],sumb[],tmpsum[],bel[],belb[],pre1[],pre2[],pre0[];
- int b[maxk],preb[maxk];
- int a[maxn],ans[maxn],prea[maxn],presm[maxn],prebg[maxn];
- int i,j,k,n,m,judlen,s;
- int jud[];
- ull jc1[maxk];
- bool u[],u1[maxk];
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- struct zs{
- int too,pre;
- }e0[maxn],e1[maxn],e2[maxn];
- int l0[maxn],l1[maxn],l2[maxn],t0,t1,t2;
- ull nowh1=,nowh2=,nowh0=;
- ull hash=,hnow=,jc,h1=,h2=,h0=;
- int kindb,kind;
- inline void ins0(int a,int b){e0[++t0].too=b;e0[t0].pre=l0[a];l0[a]=t0;}
- inline void ins1(int a,int b){e1[++t1].too=b;e1[t1].pre=l1[a];l1[a]=t1;}
- inline void ins2(int a,int b){e2[++t2].too=b;e2[t2].pre=l2[a];l2[a]=t2;}
- inline void clr(int x){
- int i,to;
- for(i=l0[x];i;i=e0[i].pre){
- to=e0[i].too;prea[to]=;if(to>x+k)continue;
- nowh0-=(ull)(to-x)*jc1[x+k-to];
- }
- for(i=l1[x];i;i=e1[i].pre){
- to=e1[i].too;presm[to]=;if(to>x+k)continue;
- nowh1-=(ull)(to-x)*jc1[x+k-to];
- }
- for(i=l2[x];i;i=e2[i].pre){
- to=e2[i].too;prebg[to]=;if(to>x+k)continue;
- nowh2-=(ull)(to-x)*jc1[x+k-to];
- }
- }
- ull mphash=,mphashb[],jjc;
- int main(){
- srand();jc=jc1[]=;
- n=read();k=read();s=read();
- judlen=min(k,min(,/n));
- for(i=;i<=judlen;i++){
- for(j=rand()%k;u1[j];j=rand()%k);
- jud[i]=j;u1[j]=;
- }
- for(i=;i<=n;i++)a[i]=read();
- for(i=;i<=k;i++){
- b[i]=read();u[b[i]]=;
- if(i>){hash*=;hash+=b[i]>=b[i-]?:;jc*=;}
- presm[i]=pre1[b[i]];prebg[i]=pre2[b[i]];preb[i]=pre0[b[i]];
- for(j=;j<b[i];j++)pre2[j]=i;for(j=b[i]+;j<=s;j++)pre1[j]=i;pre0[b[i]]=i;
- h1*=;if(presm[i])h1+=i-presm[i];
- h2*=;if(prebg[i])h2+=i-prebg[i];
- h0*=;if(preb[i])h0+=i-preb[i];jc1[i]=jc1[i-]*;
- }
- for(i=;i<=s;i++)if(u[i])kindb++,belb[i]=kindb;
- for(i=;i<=k;i++)b[i]=belb[b[i]],sumb[b[i]]++;
- memset(pre1,,sizeof(pre1));memset(pre2,,sizeof(pre2));memset(pre0,,sizeof(pre0));
- for(i=;i<=n;i++){
- presm[i]=pre1[a[i]];prebg[i]=pre2[a[i]];prea[i]=pre0[a[i]];
- pre0[a[i]]=i;for(j=;j<a[i];j++)pre2[j]=i;for(j=a[i]+;j<=s;j++)pre1[j]=i;pre0[a[i]]=i;
- ins0(prea[i],i);ins1(presm[i],i);ins2(prebg[i],i);
- }
- for(i=;i<=k;i++){
- if(i>){hnow*=;hnow+=a[i]>=a[i-]?:;}
- kind+=!sum[a[i]],sum[a[i]]++;
- nowh1*=;if(presm[i])nowh1+=i-presm[i];
- nowh2*=;if(prebg[i])nowh2+=i-prebg[i];
- nowh0*=;if(prea[i])nowh0+=i-prea[i];
- }
- int tmp;jjc=;
- for(i=;i<=k;i++){
- for(j=;j<;j++)mphashb[j]*=,mphashb[j]+=b[i]+j-;
- mphash*=,mphash+=a[i];jjc*=;
- }
- int val[]={,};
- for(i=k;i<=n;
- i++,hnow*=,hnow+=val[a[i]>=a[i-]],hnow-=jc*val[a[i-k+]>=a[i-k]]
- ,sum[a[i-k]]--,kind-=(!sum[a[i-k]])-(!sum[a[i]]),sum[a[i]]++
- ,nowh1*=,nowh1+=presm[i]?i-presm[i]:
- ,nowh2*=,nowh2+=prebg[i]?i-prebg[i]:
- ,nowh0*=,nowh0+=prea[i]?i-prea[i]:
- ,clr(i-k)
- ,mphash*=,mphash+=a[i],mphash-=jjc*a[i-k]
- )
- if(hnow==hash&&kind==kindb&&nowh1==h1&&nowh0==h0&&nowh2==h2){
- bool f1=;
- for(j=;j<;j++)if(mphash==mphashb[j]){ans[++ans[]]=i-k+;f1=;break;}
- if(!f1)continue;
- for(j=;j<;j++)if(mphash==mphashb[j]){ans[++ans[]]=i-k+;f1=;break;}
- if(!f1)continue;
- for(tmp=,j=;j<=s;j++)if(sum[j])if(sum[j]!=sumb[++tmp]){f1=;break;}
- else bel[j]=tmp;
- if(!f1)continue;
- for(j=;j<=judlen;j++)if(bel[a[i-jud[j]]]!=b[k-jud[j]]){f1=;break;}
- if(!f1)continue;
- ans[++ans[]]=i-k+;
- }
- printf("%d\n",ans[]);
- for(i=;i<=ans[];i++)printf("%d\n",ans[i]);
- return ;
- }
bzoj 1780: [Usaco2010 Feb]corral 覆盖牛棚
首先把被完全覆盖的围栏去掉,剩下的按左端点升序排序。那么右端点肯定也是升序的了。。然后计算出每段围栏,它接下去一段围栏可达到的最远距离。
枚举起点,贪心地一段一段接下去就可得到该起点的最优解。
直接这样做显然会T。。我们找出一圈围栏后,把这些围栏都指向刚好跨过一圈的那条围栏就可以避免同个解不同起点的重复计算了(看了kpm代码才会的QAQ)。
复杂度不会算...
大概是#1吧。。。
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int maxn=;
- struct fence{
- int l,r;
- }fen[maxn];
- int next[maxn],pos[maxn],jump[maxn],tmpcos[maxn];
- int i,j,L,n,m,ans,k;
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- bool cmp1(fence a,fence b){return (a.l<b.l)||(a.l==b.l&&a.r>b.r);}
- inline void get(int x){
- if(jump[x])return;
- if(fen[x].r>=L)jump[x]=x,tmpcos[x]=;else get(next[x]),jump[x]=jump[next[x]],tmpcos[x]=tmpcos[next[x]]+;
- }
- int main(){
- L=read();n=read();
- for(i=;i<=n;i++)fen[i].l=read(),fen[i].r=read()+fen[i].l;
- sort(fen+,fen++n,cmp1);
- int mx=-;int tmp=;
- for(i=;i<=n;i++)if(fen[i].r>mx)fen[++tmp]=fen[i],mx=fen[i].r;n=tmp;
- tmp=;
- for(i=;i<=n;i++){
- next[i]=next[i-];
- for(;tmp<n&&fen[tmp+].l<=fen[i].r;tmp++);
- if(tmp==i)next[i]=;else next[i]=tmp,pos[i]=fen[tmp].r;
- }
- int tmpsum,now;
- ans=;
- for(i=;i<=n;i++){
- if(!jump[i])get(i);tmpsum=tmpcos[i]+;now=jump[i];
- while(next[now]&&fen[now].r<fen[i].l+L&&tmpsum<ans)now=next[now],tmpsum++;
- if(fen[now].r>=fen[i].l+L&&tmpsum<ans)ans=tmpsum;
- }
- printf("%d\n",ans);
- return ;
- }
正常做法的话大概就是 每个围栏 向 它接下去最远的围栏连条有向边,然后就是基环内向树上的询问了?
bzoj 1698: [Usaco2007 Feb]Lilypad Pond 荷叶池塘
最短路计数。。题解说得挺详细的。。
一开始想到把连到空格子的边权设为1,结果发现这样会重复计算方案(兜了一圈边权0的再回来,放的荷叶并没有变化)
那么根据网上的题解TAT,处理出两两空格子(包括起点和终点)之间能否不经其他空格子到达。。可以到达的话就连边,权值为1。
在新图中跑最短路计数就行了。KPM实力#1。。。伏地膜
注意因为新图中的边权都为1所以最短路计数随便搞。。。如果是一般些的图的话得考虑重复计数的情况。
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #define ll long long
- using namespace std;
- const int maxn=;
- const int xx[]={-,-,,,,,-,-},yy[]={-,-,-,-,,,,};
- struct zs{
- int too,pre;
- }e[maxn*maxn*maxn*maxn];
- int map[maxn][maxn];
- int id[maxn][maxn],poi;
- int last[maxn*maxn],tot;
- int l,r,now,i,j,k,nowx,nowy,x,y,n,m,a,S,T,to;
- int dlx[maxn*maxn],dly[maxn*maxn],dis[maxn*maxn];
- ll num[maxn*maxn];
- bool u[maxn*maxn];
- inline void insert(int a,int b){
- e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;
- // printf(" %d-->%d\n",a,b);
- }
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- int main(){
- n=read();m=read();
- for(i=;i<=n;i++)for(j=;j<=m;j++){
- a=read(),id[i][j]=++poi,map[i][j]=(a==||a==||a==)?:a;
- if(a==)S=poi;if(a==)T=poi;
- }
- for(i=;i<=n;i++)for(j=;j<=m;j++)if(!map[i][j]){
- memset(u,,poi+);
- l=;r=;dlx[]=i;dly[]=j;u[id[i][j]]=;
- while(l<r){
- nowx=dlx[++l];nowy=dly[l];
- for(k=;k<;k++){
- x=nowx+xx[k];y=nowy+yy[k];
- if(x<||y<||x>n||y>m||u[id[x][y]]||map[x][y]==)continue;u[id[x][y]]=;
- if(map[x][y])dlx[++r]=x,dly[r]=y;else insert(id[i][j],id[x][y]);
- }
- }
- }
- memset(u,,poi+);
- l=;r=;dlx[]=S;num[S]=;dis[S]=;
- while(l<r){
- now=dlx[++l];u[now]=;
- if(now==T)break;
- for(i=last[now],to=e[i].too;i;i=e[i].pre,to=e[i].too)if(!u[to])
- if(!num[to])dlx[++r]=to,num[to]=num[now],dis[to]=dis[now]+;
- else if(dis[to]==dis[now]+)num[to]+=num[now];
- }
- if(num[T])printf("%d\n",dis[T]-),printf("%lld\n",num[T]);
- else puts("-1");
- // printf(" %d\n",tot);
- return ;
- }
bzoj 1737: [Usaco2005 jan]Naptime 午睡时间
dp。。设f[i][j][0]表示前i个时间段里,睡了j个时间段的最大值,但时间i没睡。f[i][j][1]表示时间i睡了,其他一样。val[i]表示在时间i睡觉的总效用值。
f[i][j][0]=max{ f[i-1][j][0],f[i-1][j][1] }
f[i][j][1]=max{ f[i-1][j-1][0],f[i-1][j-1][1]+val[i] }。
第一次我们强制不跨环,初始化f[1][1][1]=f[1][0][0]=0,此时答案是f数组最大值;第二次我们强制跨环,初始化f[1][1][1]=0,f[1][0][0]=-inf,此时答案是f[n][m][1]+val[1]。
最终答案就是两种情况的较大值。
又是#1辣。。
- #include<cstdio>
- #include<cstring>
- #include<iostream>
- using namespace std;
- const int maxn=;
- int f[maxn][],pre;
- int val[maxn];
- int i,j,n,m,ans;
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- int main(){
- n=read();m=read();
- for(i=;i<=n;i++)val[i]=read();
- memset(f,,(m+)<<);
- f[][]=f[][]=;
- for(i=;i<=n;i++)for(j=m;j;j--){
- if(f[j][]>f[j][])f[j][]=f[j][];
- f[j][]=f[j-][]+val[i];if(f[j-][]>f[j][])f[j][]=f[j-][];
- }ans=max(f[m][],f[m][]);
- memset(f,,(m+)<<);
- f[][]=;
- for(i=;i<=n;i++)for(j=m;j;j--){
- if(f[j][]>f[j][])f[j][]=f[j][];
- f[j][]=f[j-][]+val[i];if(f[j-][]>f[j][])f[j][]=f[j-][];
- }ans=max(ans,f[m][]+val[]);
- printf("%d\n",ans);
- return ;
- }
bzoj 3312: [Usaco2013 Nov]No Change
一开始以为是贪心。。结果看数据范围果断状压= =
f[i]表示已取硬币状态为i时,最多可支付的东西数。pre[i]表示前i个东西的价格和。val[i]表示第i个硬币的面值
f[i]=max{ f[i-(1<<k)]+x },((1<<k)存在于状态i中,x是使pre[ x+f[i-(1<<k) ]-pre[ f[i-(1<<k)] ] <=val[k]的最大值,也就是最多能再买多少件东西 )。
时间复杂度(2^k*k*logn)
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- using namespace std;
- const int maxn=;
- int pre[maxn],val[],two[];
- int f[(<<)+],pos[(<<)+];
- int i,j,K,n,l,r,mid,k,st,tmp,ans;
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- int main(){
- K=read();n=read();two[]=;pos[]=;
- for(i=;i<K;i++)val[i]=read();
- for(i=;i<K;i++)two[i]=two[i-]<<,pos[two[i]]=i;
- for(i=;i<=n;i++)pre[i]=read()+pre[i-];
- f[]=;int mx=<<K;
- ans=-;
- for(i=;i<mx;i++){
- for(tmp=,k=mx-i-,j=pos[k&-k];k;k-=k&-k,j=pos[k&-k])tmp+=val[j];
- if(tmp<=ans)continue;
- for(k=i,j=pos[k&-k];k;k-=k&-k,j=pos[k&-k]){
- l=st=f[i^(k&-k)];r=n;
- while(l<r&&r>f[i]){
- mid=(l+r+)>>;
- if(pre[mid]-pre[st]>val[j])r=mid-;else l=mid;
- }
- if(l>f[i])f[i]=l;
- }
- if(f[i]==n)ans=tmp;
- // printf(" %d %d\n",i,f[i]);
- }
- printf("%d\n",ans);
- return ;
- }
bzoj 1750: [Usaco2005 qua]Apple Catching
傻逼dp。。f[i][j][k]表示i秒后,牛已移动j次,在k处(k=0在左,k=1在右)
f[i][j][k]=max{ f[i-1][j][k],f[i-1][j-1][1-k] }+map[i][k],(map[i][k]表示k处在第i秒的时候有无苹果。)
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- using namespace std;
- int f[][];
- int i,j,x,n,m,ans;
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- int main(){
- n=read();m=read();
- f[][]=-;
- for(i=;i<=n;i++){
- x=read();x--;
- if(x)for(j=m;j;j--){
- if(f[j-][]>f[j][])f[j][]=f[j-][];
- if(f[j-][]>f[j][])f[j][]=f[j-][];
- f[j][]++;
- }else for(j=m;j;j--){
- if(f[j-][]>f[j][])f[j][]=f[j-][];
- if(f[j-][]>f[j][])f[j][]=f[j-][];
- f[j][]++;
- }
- f[j][x]++;
- }
- ans=max(f[m][],f[m][]);
- for(i=m-;i>=;i--){
- if(f[i][]>ans)ans=f[i][];
- if(f[i][]>ans)ans=f[i][];
- }
- printf("%d\n",ans);
- return ;
- }
bzoj 1746: [Usaco2005 open]Lazy Cows
再次验证了我是傻逼= =
因为只有两行,所以帆布的状态只有四种:只覆盖上面一行,只覆盖下面一行,两行用一块布覆盖,两行用两块布分别覆盖。
用f[i][j][0..3]表示用j块布覆盖了前i个洞后,对应以上四种状态的最小面积。预处理pos[i]表示第i个破洞的列数。
f[i][0]=min( min{ f[i-1][j][0],f[i-1][j][3] }+pos[i]-pos[i-1] , min{ f[i-1][j-1][0..3] }+1 ),(第i个洞在第一行)
f[i][1]基本同上。
f[i][2]=min{ f[i-1][j][2]+2*(pos[i]-pos[i-1]) , min{ f[i-1][j-1][0..3] }+2 }
f[i][3]=min{ min{ f[i-1][j-1][0..1] }+pos[i]-pos[i-1]+1 , min{ f[i-1][j-2][0..3] }+2 , f[i-1][j][3]+2*(pos[i]-pos[i-1]) }
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int maxn=;
- const int inf=;
- struct poi{
- bool x;int y;
- }a[maxn];
- int num[maxn],dis[maxn];
- int f[maxn][];
- int n,m,flag,K,mn,ans;
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- bool cmp(poi a,poi b){return a.y<b.y;}
- int main(){
- int i,j,now;
- n=read();K=read();m=read();
- for(i=;i<=n;i++)a[i].x=read()==,a[i].y=read();
- sort(a+,a++n,cmp);int tmp=;a[].y=a[].y;
- for(i=;i<=n;){
- flag=a[i].x+;
- for(j=i+;j<=n&&a[j].y==a[i].y;j++)flag|=a[j].x+;
- num[++tmp]=flag-;
- dis[tmp]=a[i].y-a[i-].y;
- i=j;
- }n=tmp;
- memset(f,,(n+)<<);
- f[][num[]]=max(num[],);f[][]=f[][]=;
- for(i=;i<=n;i++)for(now=dis[i],j=K-,mn=min(f[j][],f[j][]<f[j][]?f[j][]:f[j][]),f[++j][]+=now,f[j][]+=now,f[j][]+=now,f[j][]+=now;j;){
- if(!num[i]){
- if(mn<f[j][])f[j][]=mn+;
- if(f[j][]<f[j][])f[j][]=f[j][];
- f[j][]=inf;
- }else if(num[i]==){
- if(mn<f[j][])f[j][]=mn+;
- if(f[j][]<f[j][])f[j][]=f[j][];
- f[j][]=inf;
- }else f[j][]=f[j][]=inf;
- f[j][]+=now;if(mn+<f[j][])f[j][]=mn+;
- f[j][]+=now;
- j-=;if(j>=){
- mn=f[j][];if(f[j][]<mn)mn=f[j][];if(f[j][]<mn)mn=f[j][];if(f[j][]<mn)mn=f[j][];
- if(mn+<f[j+][])f[j+][]=mn+;
- }
- f[++j][]+=now;f[j][]+=now;f[j][]+=now;f[j][]+=now;
- if(f[j][]<f[j+][])f[j+][]=f[j][]+;
- if(f[j][]<f[j+][])f[j+][]=f[j][]+;
- }
- ans=inf;
- i=min(n,K);
- for(j=;j<;j++)if(f[i][j]<ans)ans=f[i][j];
- printf("%d\n",ans);
- return ;
- }
bzoj 1727: [Usaco2006 Open]The Milk Queue 挤奶队列
抱了ctl学长的大腿。。。
贪心。。如果牛A排在牛B前面比B排在A前面更优所以blabla。。具体列个式子后快排就好了。。
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- #include<algorithm>
- using namespace std;
- const int maxn=;
- int id[maxn],a[maxn],b[maxn];
- int i,end1,end2,j,n;
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- bool cmp(int x,int y){return a[x]+b[y]+(b[x]>a[y]?b[x]:a[y])<a[y]+b[x]+(b[y]>a[x]?b[y]:a[x]);}
- int main(){
- n=read();
- for(i=;i<=n;i++)a[i]=read(),b[i]=read(),id[i]=i;
- sort(id+,id++n,cmp);
- for(i=;i<=n;i++){
- j=id[i];end1+=a[j];
- if(end1<=end2)end2+=b[j];else end2=end1+b[j];
- }
- printf("%d\n",max(end1,end2));
- return ;
- }
bzoj 1736: [Usaco2005 jan]The Wedding Juicer 婚宴的榨汁机
从图的边界开始往内部跑类似最短路的。。dis[i]表示i点最大可接受高度。
dis[i]也就是从图的边界上的任意点出发,高度不递减地跑到i,途中经过的最大高度的最小值(就是水流出去的过程反过来)。
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #define ll long long
- using namespace std;
- const int maxn=;
- const int xx[]={,,,-},yy[]={,-,,};
- int map[maxn][],num[maxn],poinum,id[][];
- int dis[maxn],mp[maxn];
- bool used[maxn],full[maxn];
- int i,j,k,n,m,nx,ny,x,y,mx,now,size,to;
- ll ans;
- struct poi{int pos,dis;};
- priority_queue<poi>q;
- bool operator <(poi a,poi b){return a.dis>b.dis;}
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- int main(){
- m=read();n=read();
- for(i=;i<=n;i++)for(j=;j<=m;j++)id[i][j]=++poinum,mp[poinum]=read(),mx=max(mx,mp[poinum]);
- for(i=;i<=n;i++)for(j=;j<=m;j++)for(k=,x=id[i][j];k<;k++){
- nx=i+xx[k];ny=j+yy[k];if(nx<||nx>n||ny<||ny>m)continue;
- y=id[nx][ny];map[x][num[x]++]=y;
- }
- for(i=;i<=n;i++)for(j=;j<=m;j++)
- if(i==||i==n||j==||j==m)dis[id[i][j]]=mp[id[i][j]],full[id[i][j]]=;
- else dis[id[i][j]]=mx;
- for(i=;i<m;i++)q.push((poi){i,mp[i]}),q.push((poi){id[n][i],mp[id[n][i]]}),size+=;
- for(i=;i<=n;i++)q.push((poi){id[i][],mp[id[i][]]}),q.push((poi){id[i][m],mp[id[i][m]]}),size+=;
- while(size){
- while(size&&used[q.top().pos])q.pop(),size--;
- if(!size||q.top().dis==mx)break;
- now=q.top().pos;x=q.top().dis;used[now]=;q.pop();size--;
- for(i=;i<num[now];i++)if(dis[to=map[now][i]]>x&&!full[to]){
- if(mp[to]>x)dis[to]=mp[to],full[to]=;else dis[to]=x;
- q.push((poi){to,dis[to]});size++;
- }
- }
- for(i=;i<=n;i++)for(j=;j<=m;j++)if(!full[id[i][j]])ans+=(ll)dis[id[i][j]]-mp[id[i][j]];
- printf("%lld\n",ans);
- return ;
- }
bzoj 3408: [Usaco2009 Oct]Heat Wave 热浪
裸最短路。。。为何这么少人写
又一次调优先队列结果和正常的spfa一样快。
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<queue>
- using namespace std;
- struct zs{int too,pre,dis;}e[];
- struct poi{int pos,dis;};
- priority_queue<poi>q;
- bool operator <(poi a,poi b){return a.dis>b.dis;}
- int last[],dis[];
- bool used[];
- int i,j,s,t,a,b,x,y,z,n,m,tot,size,to;
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- int main(){
- n=read();m=read();s=read();t=read();
- for(;m;m--){
- a=read(),b=read();
- e[++tot].dis=e[tot+].dis=read();
- e[tot].too=b;e[tot].pre=last[a];last[a]=tot;
- e[++tot].too=a;e[tot].pre=last[b];last[b]=tot;
- }
- memset(dis,,(n+)<<);dis[s]=;size=;q.push((poi){s,});
- while(size&&!used[t]){
- while(size&&used[q.top().pos])q.pop(),size--;
- if(!size||dis[q.top().pos]>=dis[t]||used[t])break;
- x=q.top().pos;y=q.top().dis;q.pop();--size;used[x]=;
- for(to=e[i=last[x]].too,z=y+e[i].dis;i;to=e[i=e[i].pre].too,z=y+e[i].dis)if(dis[to]>z&&z<dis[t])
- q.push((poi){to,dis[to]=z}),size++;
- }
- printf("%d\n",dis[t]);
- return ;
- }
bzoj 2590: [Usaco2012 Feb]Cow Coupons
排序显然是错的= =懒得重新写了>_<
如果没有优惠券的话直接排序后贪心。有了优惠券后,把每头牛拆成有优惠券和没优惠券两种,把2n个数排序,注意如果买了一头优惠的牛,把它没优惠券的版本设为不可取。
无法理解为啥sort比kpm调优先队列慢TAT(虽然要排2n个数。。但常数应该是比优先队列小很多的吧。。)
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- #define ll long long
- using namespace std;
- bool u[];
- int id[],a[];
- int i,j,n,k,ans,n1;
- ll m;
- int ra;char rx;
- inline int read(){
- rx=getchar();ra=;
- while(rx<''||rx>'')rx=getchar();
- while(rx>=''&&rx<='')ra*=,ra+=rx-,rx=getchar();return ra;
- }
- bool cmp(int x,int y){return a[x]<a[y];}
- int main(){
- n=read();k=read();scanf("%lld",&m);
- for(i=;i<=n;i++)id[i]=i,id[i+n]=i+n,a[i]=read(),a[i+n]=read();
- n1=n<<;
- sort(id+,id++n1,cmp);
- for(i=,j=id[];i<=n1&&m>;j=id[++i])if(m>=a[j]&&!u[j>n?j-n:j]&&(j<=n||k))
- m-=a[j],u[j>n?j-n:j]=,ans++,k-=j>n;
- printf("%d\n",ans);
- return ;
- }
完结撒花[鼓掌熊]总共大概106道吧。。
bzoj usaco 金组水题题解(2.5)的更多相关文章
- bzoj usaco 金组水题题解(1)
UPD:我真不是想骗访问量TAT..一开始没注意总长度写着写着网页崩了王仓(其实中午的时候就时常开始卡了= =)....损失了2h(幸好长一点的都单独开了一篇)....吓得赶紧分成两坨....TAT. ...
- bzoj usaco 金组水题题解(2)
续.....TAT这回不到50题编辑器就崩了.. 这里塞40道吧= = bzoj 1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害 比较经典的最小割?..然而 ...
- BZOJ USACO 银组 水题集锦
最近刷银组刷得好欢快,好像都是水题,在这里吧他们都记录一下吧(都是水题大家一定是道道都虐的把= =)几道比较神奇的题到时再列出来单独讲一下吧= =(其实我会说是BZOJ蹦了无聊再来写的么 = =) [ ...
- NOIP2018初赛普及组原题&题解
NOIP2018初赛普及组原题&题解 目录 NOIP2018初赛普及组原题&题解 原题&答案 题解 单项选择题 第$1$题 第$2$题 第$3$题 第$4$题 第$5$题 第$ ...
- World Finals 2017 (水题题解)
看大佬做2017-WF,我这种菜鸡,只能刷刷水题,勉强维持生活. 赛后补补水题. 题目pdf链接,中文的,tls翻译的,链接在这里 个人喜欢在vjudge上面刷题. E Need for Speed ...
- noip2008普及组3题题解-rLq
(第一次写题解,随意喷) (只是前一天的作业哈) (先凑个数) 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏.游戏规则是这样的:n个同学站成一个圆圈 ...
- 2006-2007 ACM-ICPC | POJ3380 POJ3384 POJ3385 水题题解
// CF比赛链接:http://codeforces.com/gym/101650 // POJ链接:http://poj.org/searchproblem?field=source&ke ...
- noip2008普及组4题题解-rLq
(啊啊啊终于补到了今天的作业了) 本题地址:http://www.luogu.org/problem/show?pid=1058 题目描述 小渊是个聪明的孩子,他经常会给周围的小朋友们将写自己认为有趣 ...
- Cmd2001的毒瘤水题题解
怕不是我再不写题解这题就该成没人做也没人会的千古谜题了...... T1: 仔细分析题面,发现相同就是广义SAM上节点相同,相似就是广义SAM上为从根到某个点路径的前缀..直接SAM上跑从根开始,每个 ...
随机推荐
- Vagrant安装完lnmp后,配置linux和windows共享文件并配置虚拟主机访问项目
虚拟机目录下的Vagrantfile文件是vagrant的配置文件,如果想把虚拟机当作一台服务器,可以通过ip访问,需要修改配置文件进行配置. (1)第一步:打开虚拟机目录下的Vagrantfile文 ...
- Mac中Eclipse安装和使用svn
Eclipse版本为Neon Release (4.6.0) 安装svn 安装HomeBrew 在终端中输入 ruby -e "$(curl -fsSL https://raw.github ...
- awk 字符拼接
i-6gdkkemx 2 2 #cat cpu.txt | awk '{print $1,$2"核"$3"G"}' i-6gdkkemx 2核2G
- Kotlin——最详细的数据类、密封类详解
在前面几个章节章节中,详细的讲解了Koltin中的接口类(Interface).枚举类(Enmu),还不甚了解的可以查看我的上一篇文章Kotlin--接口类.枚举类详解.当然,在Koltin中,除了接 ...
- 496. Next Greater Element I
You are given two arrays(without duplicates)nums1andnums2wherenums1's elements are subset ofnums2. F ...
- Hawk原理:通过IEnumerable实现通用的ETL管道
针对IEnumerable已经有多篇文章,本篇介绍如何使用IEnumerable实现ETL. ETL,是英文 Extract-Transform-Load 的缩写,用来描述将数据从来源端经过萃取(ex ...
- PHP (超文本预处理器)
PHP(外文名:PHP: Hypertext Preprocessor,中文名:"超为本预处理器")是一种通用开源脚本语言.语法吸收了C语言.java和Rerl的特点,利于学习,使 ...
- python基础知识——字符串详解
大多数人学习的第一门编程语言是C/C++,个人觉得C/C++也许是小白入门的最合适的语言,但是必须承认C/C++确实有的地方难以理解,初学者如果没有正确理解,就可能会在使用指针等变量时候变得越来越困惑 ...
- BCL和CoreFx的区别
bcl是.netframework clr 的基础库corefx是.net core clr的基础库
- Ajax异步提交登录(2)--登录使用
http://cjp1989.iteye.com/blog/1740964 1.Ajax的原理: Ajax的原理就是:通过javascript的方式,将前台数据通过xmlhttp对象传递到后台,后台在 ...