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)的更多相关文章

  1. bzoj usaco 金组水题题解(1)

    UPD:我真不是想骗访问量TAT..一开始没注意总长度写着写着网页崩了王仓(其实中午的时候就时常开始卡了= =)....损失了2h(幸好长一点的都单独开了一篇)....吓得赶紧分成两坨....TAT. ...

  2. bzoj usaco 金组水题题解(2)

    续.....TAT这回不到50题编辑器就崩了.. 这里塞40道吧= = bzoj 1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害 比较经典的最小割?..然而 ...

  3. BZOJ USACO 银组 水题集锦

    最近刷银组刷得好欢快,好像都是水题,在这里吧他们都记录一下吧(都是水题大家一定是道道都虐的把= =)几道比较神奇的题到时再列出来单独讲一下吧= =(其实我会说是BZOJ蹦了无聊再来写的么 = =) [ ...

  4. NOIP2018初赛普及组原题&题解

    NOIP2018初赛普及组原题&题解 目录 NOIP2018初赛普及组原题&题解 原题&答案 题解 单项选择题 第$1$题 第$2$题 第$3$题 第$4$题 第$5$题 第$ ...

  5. World Finals 2017 (水题题解)

    看大佬做2017-WF,我这种菜鸡,只能刷刷水题,勉强维持生活. 赛后补补水题. 题目pdf链接,中文的,tls翻译的,链接在这里 个人喜欢在vjudge上面刷题. E Need for Speed ...

  6. noip2008普及组3题题解-rLq

    (第一次写题解,随意喷) (只是前一天的作业哈) (先凑个数) 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏.游戏规则是这样的:n个同学站成一个圆圈 ...

  7. 2006-2007 ACM-ICPC | POJ3380 POJ3384 POJ3385 水题题解

    // CF比赛链接:http://codeforces.com/gym/101650 // POJ链接:http://poj.org/searchproblem?field=source&ke ...

  8. noip2008普及组4题题解-rLq

    (啊啊啊终于补到了今天的作业了) 本题地址:http://www.luogu.org/problem/show?pid=1058 题目描述 小渊是个聪明的孩子,他经常会给周围的小朋友们将写自己认为有趣 ...

  9. Cmd2001的毒瘤水题题解

    怕不是我再不写题解这题就该成没人做也没人会的千古谜题了...... T1: 仔细分析题面,发现相同就是广义SAM上节点相同,相似就是广义SAM上为从根到某个点路径的前缀..直接SAM上跑从根开始,每个 ...

随机推荐

  1. JAVA中的设计模式一(单例模式)

    单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个 ...

  2. [array] leetCode-27. Remove Element - Easy

    27. Remove Element - Easy descrition Given an array and a value, remove all instances of that value ...

  3. Who's in the Middle

    FJ is surveying his herd to find the most average cow. He wants to know how much milk this 'median' ...

  4. bat获取系统时间修改系统密码

    @echo off %1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe&q ...

  5. Java自己动手写连接池三

    Java自己动手写连接池三,核心代码; package com.kama.cn; import java.sql.Connection;import java.util.ArrayList;impor ...

  6. Java设计模式之(一)------单例模式

    1.什么是单例模式? 采取一定的办法保证在整个软件系统中,单例模式确保对于某个类只能存在一个实例.有如下三个特点: ①.单例类只能有一个实例 ②.单例类必须自己创建自己的实例 ③.单例类必须提供外界获 ...

  7. TensorFlow常用的函数

    TensorFlow中维护的集合列表 在一个计算图中,可以通过集合(collection)来管理不同类别的资源.比如通过 tf.add_to_collection 函数可以将资源加入一个 或多个集合中 ...

  8. javascript中name,value等属于保留字

    前几天在练习js代码的时候,碰到了一个坑,这是让人醉了. html代码如下: <div> <div> <!--输入 123456--> <lable>请 ...

  9. Pycharm使用总结

    1.代码整体向右移动 按住Win+TAB可以快速向右缩进一个tab 的距离,按住Shift + TAB反方向前进一个TAB距离 2.Model加入get,set 方法 在编辑框中右击,选择genera ...

  10. Redis学习之一VMWare Pro虚拟机安装和Linux系统的安装

    一.引言 设计模式写完了,相当于重新学了一遍,每次学习都会有不同的感受,对设计模式的理解又加深了,理解的更加透彻了.还差一篇关于设计模式的总结的文章了,写完这篇总结性的文章,设计模式的文章就暂时要告一 ...