coins feast 题解_bzoj Usaco补完计划(优先级 Gold>Silver>资格赛)

听说KPM初二暑假就补完了啊%%%

先刷Gold再刷Silver(因为目测没那么多时间刷Silver,方便以后TJ2333(雾

按AC数降序刷

-------------------------------------------------------------------------------------------------------

bzoj1597: [Usaco2008 Mar]土地购买

斜率优化DP

h升序,w降序。

f[i]=min(f[j]+h[i]*w[j+1])

(h[j]-h[k])/(w[k+1]-w[j+1])

所以下凸,斜率不下降

#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010;struct poi{inth,w;}a[maxn];intn,m,x,y,z,l,r,tot,h[maxn],w[maxn];

ll q[maxn],f[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.h==b.h?a.w

{

read(n);for(int i=1;i<=n;i++)read(a[i].h),read(a[i].w);

sort(a+1,a+1+n,cmp);for(int i=1;i<=n;i++)

{while(tot&&w[tot]<=a[i].w)tot--;

h[++tot]=a[i].h;w[tot]=a[i].w;

}

l=0;r=0;for(int i=1;i<=tot;i++)

{while(l

f[i]=f[q[l]]+1ll*h[i]*w[q[l]+1];while(lxl(q[r],i))r--;

q[++r]=i;

}

printf("%lld\n",f[tot]);return 0;

}

View Code

bzoj1699: [Usaco2007 Jan]Balanced Lineup排队

裸RMQ

#include#include#include#include#include

using namespacestd;int n,m,f[200010][20],g[200010][20],l,r,k;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}int log2(int x){return log(x)/log(2);}int exp(int x){return 1<

{for(int j=1;j<=log2(n);j++)for(int i=1;i<=n-exp(j)+1;i++)

f[i][j]=max(f[i][j-1],f[i+exp(j-1)][j-1]),g[i][j]=min(g[i][j-1],g[i+exp(j-1)][j-1]);

}intmain()

{

read(n);read(m);for(int i=1;i<=n;i++)read(f[i][0]),g[i][0]=f[i][0];

rmq();for(int i=1;i<=m;i++)

{

read(l);read(r);

k=log2(r-l+1);

printf("%d\n",max(f[l][k],f[r-exp(k)+1][k])-min(g[l][k],g[r-exp(k)+1][k]));

}

}

View Code

bzoj1666: [Usaco2006 Oct]Another Cow Number Game 奶牛的数字游戏

直接模拟

#include#include#include#include

using namespacestd;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intans,n;intmain()

{

read(n);while(n!=1)

{

ans++;if(n&1)n=n*3+1;else n/=2;

}

printf("%d\n",ans);

}

View Code

bzoj1692: [Usaco2007 Dec]队列变换

hash+二分logn比较正反后缀字典序

#include#include#include#include

#define ull unsigned long long

using namespacestd;

ull mul[100010],hs[100010],ophs[100010],L,R,l,r,mid,len,num,n;char s[100010];void read(ull &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intlcp()

{

l=1;r=R-L+1;while(l

{

mid=(l+r+1)>>1;int hs1=hs[L+mid-1]-hs[L-1]*mul[mid];int hs2=ophs[R-mid+1]-ophs[R+1]*mul[mid];if(hs1!=hs2)r=mid-1;else l=mid;

}returnl;

}boolcmp()

{if(s[L]!=s[R])return s[L]>s[R];

len=lcp();if(len==R-L+1)return 1;else return s[L+len]>s[R-len];

}intmain()

{

read(n);for(int i=1;i<=n;i++)for(s[i]=getchar();s[i]'Z';s[i]=getchar());

mul[0]=1;for(int i=1;i<=n;i++)mul[i]=mul[i-1]*27;for(int i=1;i<=n;i++)hs[i]=hs[i-1]*27+(ull)s[i]-'A';for(int i=n;i;i--)ophs[i]=ophs[i+1]*27+(ull)s[i]-'A';

L=1;R=n;num=1;for(int i=1;i<=n;i++,num++)

{

printf("%c",cmp()?s[R--]:s[L++]);if(num==80)printf("\n"),num=0;

}

}

View Code

bzoj1717: [Usaco2006 Dec]Milk Patterns 产奶的模式

可重叠k次最长重复子串

二分答案,h[]>=mid的分一段,如果有一段的后缀个数>=k则合法。

多关键字基数排序。

a[]为A关键字

b[]为B关键字排序后的数组(作为排序后数组的答案)

for(int i=1;i<=n;i++)sum[a[i]]++;

for(int i=1;i<=n;i++)sum[i]+=sum[i-1];

for(int i=n;i;i--)sa[sum[a[b[i]]]=b[i],sum[a[b[i]]]--;

而在SA中

for(int i=1;i<=n;i++)rk[i]=trk[tsa[i]],sum[rk[i]]++;

for(int i=2;i<=m;i++)sum[i]+=sum[i-1];

for(int i=n;i;i--)sa[sum[rk[i]]]=tsa[i],sum[rk[i]]--;

A B关键字就是字符的字典序。

a[]实际上是trk[]

b[]是tsa[]

定义了一个rk[]=trk[tsa[]]

那么多关键字排序的时候就sa[sum[trk[tsa[]]]]变成了sa[sum[rk[]]]。

#include#include#include#include

using namespacestd;const int maxn=100010;intn,m,p,k,l,r;intsum[maxn],rk[maxn],sa[maxn],trk[maxn],tsa[maxn],h[maxn],s[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}voidsuffix()

{for(int i=1;i<=n;i++)sum[s[i]]++;for(int i=1;i<=255;i++)sum[i]+=sum[i-1];for(int i=n;i;i--)sa[sum[s[i]]]=i,sum[s[i]]--;

rk[sa[1]]=1;p=1;for(int i=2;i<=n;i++)rk[sa[i]]=(s[sa[i]]!=s[sa[i-1]])?++p:p;

m=p;int j=1;while(m

{

memcpy(trk,rk,sizeof(rk));memset(sum,0,sizeof(sum));p=0;for(int i=n-j+1;i<=n;i++)tsa[++p]=i;for(int i=1;i<=n;i++)if(sa[i]>j)tsa[++p]=sa[i]-j;for(int i=1;i<=n;i++)rk[i]=trk[tsa[i]],sum[rk[i]]++;for(int i=2;i<=m;i++)sum[i]+=sum[i-1];for(int i=n;i;i--)sa[sum[rk[i]]]=tsa[i],sum[rk[i]]--;

rk[sa[1]]=1;p=1;for(int i=2;i<=n;i++)rk[sa[i]]=(trk[sa[i]]!=trk[sa[i-1]]||trk[sa[i]+j]!=trk[sa[i-1]+j])?++p:p;

m=p;j*=2;

}

h[1]=0;p=0;for(int i=1;i<=n;i++)

{if(rk[i]==1)continue;

j=sa[rk[i]-1];while(s[i+p]==s[j+p])p++;

h[rk[i]]=p;if(p)p--;

}

}bool check(intmid)

{int num=1;for(int i=1;i<=n;i++)if(h[i]>=mid)num++;else{if(num>=k)return 1;

num=1;

}if(num>=k)return 1;return 0;

}intmain()

{

read(n);read(k);for(int i=1;i<=n;i++)read(s[i]);

suffix();

l=0;r=n;while(l

{int mid=(l+r+1)>>1;if(check(mid))l=mid;else r=mid-1;

}

printf("%d\n",l);

}

View Code

bzoj1724: [Usaco2006 Nov]Fence Repair 切割木板

堆,每次合并最小的两个木板

#include#include#include#include#include

#define ll long long

using namespacestd;struct poi{intsum;};

priority_queueq;bool operator b.sum;};intx,y,n;

ll ans;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);for(int i=1;i<=n;i++)read(x),q.push((poi){x});for(int i=1;i

{

x=q.top().sum;q.pop();

y=q.top().sum;q.pop();

ans+=x+y;

q.push((poi){x+y});

}

printf("%lld\n",ans);

}

View Code

bzoj1572: [Usaco2009 Open]工作安排Job

能加就加;加不进去还是加进去,然后删掉最小的。

#include#include#include#include#include#include

#define ll long long

using namespacestd;struct poi{ll d,p;}a[100010];structtjm{ll p;};

priority_queueq;bool operatorb.p;}

ll n,x,t;long longans;void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return (a.db.p));}intmain()

{

read(n);for(int i=1;i<=n;i++)read(a[i].d),read(a[i].p);

sort(a+1,a+1+n,cmp);

t=1;for(int i=1;i<=n;i++)

{if(a[i].d

{

x=q.top().p;if(a[i].p>x)

{

ans=ans-x+a[i].p;

q.pop();

q.push((tjm){a[i].p});

}

}else{

t++;

q.push((tjm){a[i].p});

ans+=a[i].p;

}

}

printf("%lld\n",ans);

}

View Code

bzoj1726: [Usaco2006 Nov]Roadblocks第二短路

次短路模板

#include#include#include#include

using namespacestd;const int inf=1000000000,maxn=5010,maxm=500010;struct zs{inttoo,sum,pre;}e[maxm];intn,m,tot,front,rear;intdist[maxn],dist2[maxn],v[maxn],last[maxn],h[maxm],x,y,z;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,int z){e[++tot].too=y;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}void spfa(intx)

{for(int i=1;i<=n;i++)dist[i]=inf,dist2[i]=inf,v[i]=0;

v[x]=1;dist[x]=0;rear=1;front=0;h[1]=x;while(front!=rear)

{int now=h[++front];if(front==maxm)front=-1;for(int i=last[now];i;i=e[i].pre)

{int too=e[i].too,dis=dist[now]+e[i].sum;bool flag=0;if(dist[too]>dis)dist2[too]=dist[too],dist[too]=dis,flag=1;if(dist[too]dis)dist2[too]=dis,flag=1;if(dist2[too]>dist2[now]+e[i].sum)dist2[too]=dist2[now]+e[i].sum,flag=1;if(flag&&!v[too])

{

v[too]=1;

h[++rear]=too;if(rear==maxm)rear=-1;

}

}

v[now]=0;

}

}intmain()

{

read(n);read(m);for(int i=1;i<=m;i++)

read(x),read(y),read(z),add(x,y,z),add(y,x,z);

spfa(1);

printf("%d\n",dist2[n]);return 0;

}

View Code

bzoj1579: [Usaco2009 Feb]Revamping Trails 道路升级

分层图(优先队列好慢。。。但是不会被卡

#include#include#include#include#include

#define ll long long

using namespacestd;const int inf=1000000000,maxn=10010,maxm=500010;structpoi{ll dis,pos,ceng;};struct zs{inttoo,sum,pre;}e[maxm];

priority_queueq;bool operatorb.dis;}intn,m,k,tot,x,y,z,last[maxn];;

ll dist[maxn][30],ans;bool v[maxn][30];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,int z){e[++tot].too=y;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}void spfa(intx)

{for(int i=1;i<=n;i++)for(int j=0;j<=k;j++)dist[i][j]=inf,v[i][j]=0;

v[x][0]=1;dist[x][0]=0;q.push((poi){0,x});while(!q.empty())

{

poi now=q.top();int ceng=now.ceng;q.pop();for(int i=last[now.pos];i;i=e[i].pre)

{int too=e[i].too;if(dist[too][ceng]>dist[now.pos][ceng]+e[i].sum)

{

dist[too][ceng]=dist[now.pos][ceng]+e[i].sum;if(!v[too][ceng])

{

v[too][ceng]=1;

q.push((poi){dist[too][ceng],too,ceng});

}

}if(dist[too][ceng+1]>dist[now.pos][ceng]&&ceng

{

dist[too][ceng+1]=dist[now.pos][ceng];if(!v[too][ceng+1])

{

v[too][ceng+1]=1;

q.push((poi){dist[too][ceng+1],too,ceng+1});

}

}

}

v[now.pos][ceng]=0;

}

}intmain()

{

read(n);read(m);read(k);for(int i=1;i<=m;i++)read(x),read(y),read(z),add(x,y,z),add(y,x,z);

spfa(1);

ans=inf;for(int i=0;i<=k;i++)

ans=min(ans,dist[n][i]);

printf("%lld\n",ans);

}

View Code

bzoj1690: [Usaco2007 Dec]奶牛的旅行

最优比率环。以前写过篇题解,当时没有真的懂,看了一下分数规划终于明白了。已经更新以前的题解。

#include#include#include#include#include

using namespacestd;struct zs{int too,pre;double dis;}e[10001];struct poi{int pos;doubledis;};

priority_queueq;bool operator 1e-3;}int n,m,x,y,now,tot,num[1001],last[1001];bool v[1001];double l,r,mid,dis[1001],fun[1001];bool spfa(intx)

{for(int i=1;i<=n;i++)dis[i]=23333333;v[x]=true;q.push((poi){1,0});dis[1]=0;while(!q.empty())

{inti,too;for(i=last[now=q.top().pos],too=e[i].too,q.pop();i;i=e[i].pre,too=e[i].too)

{double dist=e[i].dis*mid-fun[too];if(dis[too]-dis[now]-dist>1e-3)

{

dis[too]=dis[now]+dist;if(!v[too])v[too]=1,q.push((poi){too,e[i].dis}),num[too]++;if(num[too]>233)return 1;

}

}

v[now]=0;

}return 0;

}intmain()

{

scanf("%d %d",&n,&m);for(int i=1;i<=n;i++)scanf("%lf",&fun[i]);for(int i=1;i<=m;i++)

{

scanf("%d %d %lf",&x,&y,&e[++tot].dis);

e[tot].too=y;e[tot].pre=last[x];last[x]=tot;

}

l=0;r=10000;while(r-l>1e-3)

{

memset(v,0,sizeof(v));

memset(num,0,sizeof(num));

mid=(l+r)/2;if(spfa(1))l=mid;else r=mid;

}

printf("%.2lf",l);

}

View Code

bzoj1711: [Usaco2007 Open]Dining吃饭

三分图,牛i拆成i和i',S连食物,食物连i,i'连饮料,饮料连T,最大流。

脑洞大开问了下CZL,如果有多一种种类的话就把牛右边改成100*100个点表示另外两种怎么选,自己yy的写法被CZL随手叉掉,还学习了一波随机化的姿势和卡掉随机化的姿势,受益匪浅嘿嘿嘿

#include#include#include#include

using namespacestd;const int inf=1000000000,maxn=60010;struct poi{int too,pre,cf;}e[500010];intn,m,tot,ans,x,y,z,front,rear,fd,dk,ffd,ddk,sum;inth[maxn],v[maxn],last[maxn],dis[maxn],cur[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,intz)

{

e[++tot].too=y;e[tot].cf=z;e[tot].pre=last[x];last[x]=tot;

e[++tot].too=x;e[tot].pre=last[y];last[y]=tot;

}boolbfs()

{for(int i=0;i<=sum;i++)v[i]=0,dis[i]=-1;

dis[0]=0;v[0]=1;h[1]=0;front=0;rear=1;while(front!=rear)

{int now=h[++front];if(front==maxn)front=-1;for(int i=last[now];i;i=e[i].pre)

{int too=e[i].too;if(!v[too]&&e[i].cf)

{

dis[too]=dis[now]+1;if(too==sum)return 1;

v[too]=1;h[++rear]=too;if(rear==maxn)rear=-1;

}

}

}return 0;

}int dfs(int x,intf)

{int flow=0,tmp;if(x==sum)returnf;for(int &i=cur[x];i;i=e[i].pre)

{int too=e[i].too;if(dis[too]==dis[x]+1&&e[i].cf)

{

tmp=dfs(too,min(f-flow,e[i].cf));

e[i].cf-=tmp;e[i^1].cf+=tmp;flow+=tmp;if(f==flow)returnf;

}

}returnflow;

}voiddinic()

{while(bfs())

{for(int i=0;i<=sum;i++)cur[i]=last[i];

ans+=dfs(0,inf);

}

}intmain()

{

tot=1;

read(n);read(fd);read(dk);sum=fd+n*2+dk+1;for(int i=1;i<=fd;i++)add(0,i,1);for(int i=1;i<=dk;i++)add(i+fd+n*2,sum,1);for(int i=1;i<=n;i++)add(i+fd,i+n+fd,1);for(int i=1;i<=n;i++)

{

read(ffd);read(ddk);for(int j=1;j<=ffd;j++)

{

read(x);

add(x,i+fd,1);

}for(int j=1;j<=ddk;j++)

{

read(x);

add(i+n+fd,x+fd+n*2,1);

}

}

dinic();

printf("%d\n",ans);

}

View Code

bzoj1708: [Usaco2007 Oct]Money奶牛的硬币

裸完全(无限?)背包。

#include#include#include#include

#define ll long long

using namespacestd;

ll n,v,x,f[10010];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(v);read(n);

f[0]=1;for(int i=1;i<=v;i++)

{

read(x);for(int j=x;j<=n;j++)

f[j]+=f[j-x];

}

printf("%lld\n",f[n]);return 0;

}

View Code

bzoj1827: [Usaco2010 Mar]gather 奶牛大集会

树上处理题。第一次dfs记录下size[x]表示子树有几只牛和dis[x]表示子树所有牛到x的距离,第二次求总距离,每次到子节点时,总距离就加上边权*(n-size[son]),减去边权*(n-size[son]),也就是加上边权*(n-2*size[son])。

#include#include#include#include

#define ll long long

using namespacestd;const int maxn=100010;struct poi{int too,pre,sum;}e[500010];intlast[maxn];

ll n,x,y,z,tot,cnt;

ll dis[maxn],size[maxn],ans;void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,int z){e[++tot].too=y;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}void dfs(int x,intfa)

{for(int i=last[x];i;i=e[i].pre)

{if(e[i].too==fa)continue;

dfs(e[i].too,x);

size[x]+=size[e[i].too];

dis[x]+=dis[e[i].too]+size[e[i].too]*e[i].sum;

}

}void dfs2(int x,intfa,ll dist)

{

ans=min(ans,dist);for(int i=last[x];i;i=e[i].pre)

{if(e[i].too==fa)continue;

ll sum=e[i].sum*(cnt-2*size[e[i].too]);

dfs2(e[i].too,x,dist+sum);

}

}intmain()

{

read(n);for(int i=1;i<=n;i++)read(size[i]),cnt+=size[i];for(int i=1;i

dfs(1,0);

ans=dis[1];

dfs2(1,0,dis[1]);

printf("%lld\n",ans);return 0;

}

View Code

bzoj1725: [Usaco2006 Nov]Corn Fields牧场的安排

状压

#include#include#include#include

#define ll long long

using namespacestd;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intn,m,x;

ll ans,f[20][50100],state[20];bool v[50100];intmain()

{

read(n);read(m);for(int i=1;i<=n;i++)

{for(int j=1;j<=m;j++)

{

read(x);if(x)

state[i]|=(1<

}

}int st=(1<

v[0]=1;for(int i=1;i<=st;i++)

{int flag=1;for(int j=1;j>(j-1))&1))&((i>>j)&1)==1)

{

flag=0;break;

}

v[i]=flag;

}

f[0][0]=1;for(int i=1;i<=n;i++)for(int j=0;j<=st;j++)if(v[j])if((j|state[i])==state[i])for(int k=0;k<=st;k++)if(v[k])if((k|state[i-1])==state[i-1])if((j&k)==0)

f[i][j]=(f[i][j]+f[i-1][k])%100000000;for(int i=0;i<=st;i++)

ans=(ans+f[n][i])%100000000;

printf("%lld\n",ans);return 0;

}

View Code

bzoj1592: [Usaco2008 Feb]Making the Grade 路面修整

首先可以证明一个结论,最后修改出的序列的数字还是原序列的数字,因为是不下降或者不上升,直接改到一样显然是最优的,不然必然会多改一点。

于是把高度离散化,枚举i和高度就行了,前一个路面的高度可以直接记录最小值。

#include#include#include#include#include#include

using namespacestd;const int maxn=2010,inf=2147483647;struct poi{intpos,sum;}a[maxn];intn,ht[maxn],lisan[maxn],ans,f[maxn][maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.sum

{

read(n);for(int i=1;i<=n;i++)read(a[i].sum),a[i].pos=i;

sort(a+1,a+1+n,cmp);for(int i=1;i<=n;i++)ht[a[i].pos]=a[i].sum,lisan[a[i].pos]=i;for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)f[i][j]=inf;for(int i=0;i<=n;i++)f[0][i]=0;for(int i=1;i<=n;i++)

{int mn=inf;for(int j=1;j<=n;j++)

{

mn=min(mn,f[i-1][j]);

f[i][j]=min(f[i][j],mn)+abs(a[j].sum-ht[i]);

}

}

ans=f[n][1];for(int i=2;i<=n;i++)ans=min(ans,f[n][i]);for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)f[i][j]=inf;for(int i=0;i<=n;i++)f[0][i]=0;

lisan[0]=n;for(int i=1;i<=n;i++)

{int mn=inf;for(int j=n;j;j--)

{

mn=min(mn,f[i-1][j]);

f[i][j]=min(f[i][j],mn)+abs(a[j].sum-ht[i]);

}

}for(int i=1;i<=n;i++)ans=min(ans,f[n][i]);

printf("%d\n",ans);

}

View Code

bzoj2442: [Usaco2011 Open]修剪草坪

DP+单调队列优化

学会了DP的巧妙姿势,如果可以选和不选求最大值可以尝试直接求不选的最小值,好写很多。

#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=100010;intn,k,a[maxn],q[maxn],l,r;

ll sum,ans,f[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(k);for(int i=1;i<=n;i++)read(a[i]),sum+=a[i];for(int i=1;i<=n;i++)

{while((i-q[l]>k+1)&&(l<=r))l++;

f[i]=f[q[l]]+a[i];while((l<=r)&&(f[i]

q[++r]=i;

}

ans=1000000000000000000;for(int i=n-k;i<=n;i++)

ans=min(ans,f[i]);

printf("%lld\n",sum-ans);return 0;

}

View Code

bzoj1576: [Usaco2009 Jan]安全路经Travel

树链剖分或并查集。树剖以后补。

跑出最短路径树就是这题了。

树链剖分:

#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1000000000;struct gg{intdis,pos;};

priority_queueq;bool operatorb.dis;}struct poi{intx,too,pre,sum;}e[maxn];struct tjm{intsum,tag;}a[maxn];struct zs{intx,y,len;}edge[maxn];intn,m,x,y,z,flag,tot,tot2,cnt;intlast[maxn],size[maxn],fa[maxn],dep[maxn],son[maxn],w[maxn],top[maxn],dist[maxn],eg[maxn];boolused[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,int z){e[++tot].too=y;e[tot].x=x;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}void dfs1(intx)

{

size[x]=1;for(int i=last[x];i;i=e[i].pre)

{int too=e[i].too;if(fa[too]==x&&too!=fa[x])

{

dep[too]=dep[x]+e[i].sum;

dfs1(too);if(size[too]>size[son[x]])son[x]=too;

size[x]+=size[too];

}

}

}void dfs2(int x,inttp)

{

w[x]=++cnt;top[x]=tp;if(son[x])dfs2(son[x],tp);for(int i=last[x];i;i=e[i].pre)if(e[i].too!=son[x]&&e[i].too!=fa[x]&&fa[e[i].too]==x)

dfs2(e[i].too,e[i].too);

}void pushdown(intx)

{if(a[x].tag==inf)return;int tag=a[x].tag;a[x].tag=inf;

a[x<<1].tag=min(tag,a[x<<1].tag);

a[x<<1|1].tag=min(tag,a[x<<1|1].tag);

}void update(int x,int nl,int nr,int l,int r,intdelta)

{if(l<=nl&&nr<=r)a[x].tag=min(a[x].tag,delta);else{int mid=(nl+nr)>>1;if(l<=mid)update(x<<1,nl,mid,l,r,delta);if(r>mid)update(x<<1|1,mid+1,nr,l,r,delta);

}

}

ll query(int x,int nl,int nr,intnum)

{if(nl!=nr)pushdown(x);if(nl==num&&nr==num)returna[x].tag;else{int mid=(nl+nr)>>1;if(nl<=num&&num<=mid)return query(x<<1,nl,mid,num);if(mid

}

}void work(int x,int y,intlen)

{int f1=top[x],f2=top[y];while(f1!=f2)

{if(dep[f1]

update(1,1,cnt,w[f1],w[x],len);

x=fa[f1];f1=top[x];

}if(x==y)return;if(dep[x]

update(1,1,cnt,w[son[y]],w[x],len);

}void build(int x,int l,intr)

{

a[x].tag=inf;int mid=(l+r)>>1;if(l!=r)build(x<<1,l,mid),build(x<<1|1,mid+1,r);

}void spfa(intx)

{boolv[maxn];for(int i=1;i<=n;i++)dist[i]=inf,v[i]=0;

v[x]=1;dist[x]=0;q.push((gg){0,x});while(!q.empty())

{int now=q.top().pos;q.pop();for(int i=last[now];i;i=e[i].pre)

{int too=e[i].too;if(dist[too]>dist[now]+e[i].sum)

{

dist[too]=dist[now]+e[i].sum;

dep[too]=dep[now]+e[i].sum;

fa[too]=now;eg[too]=i;if(!v[too])

{

v[too]=1;

q.push((gg){dist[too],too});

}

}

}

v[now]=0;

}

}intmain()

{

tot=1;

read(n);read(m);for(int i=1;i<=m;i++)

{

read(x);read(y);read(z);

add(x,y,z),add(y,x,z);

}

spfa(1);for(int i=1;i<=n;i++)used[eg[i]]=used[eg[i]^1]=1;for(int i=1;i<=tot;i++)if(!used[i])

{

edge[++tot2].x=e[i].x;edge[tot2].y=e[i].too;

edge[tot2].len=e[i].sum+dep[e[i].x]+dep[e[i].too];

}

dfs1(1);dfs2(1,1);build(1,1,n);for(int i=1;i<=tot2;i++)

work(edge[i].x,edge[i].y,edge[i].len);for(int i=2;i<=n;i++)

{int ans=query(1,1,cnt,w[i]);if(ans!=inf)printf("%d\n",ans-dep[i]);else printf("-1\n");

}return 0;

}

View Code

并查集:

#include#include#include#include#include#include

using namespacestd;const int inf=1000000000,maxn=500010;struct zs{intx,too,sum,pre;}e[maxn];struct poi{intdis,pos;};struct tjm{intlen,x,y;}edge[maxn];

priority_queueq;bool operatorb.dis;}intn,m,x,y,z,tot,tot2;intlast[maxn],dist[maxn],h[maxn],fq[maxn],eg[maxn],fa[maxn],v[maxn];boolused[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,int z){e[++tot].x=x;e[tot].too=y;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}void spfa(intx)

{boolv[maxn];for(int i=1;i<=n;i++)dist[i]=inf,v[i]=0;

v[x]=1;dist[x]=0;q.push((poi){0,x});while(!q.empty())

{int now=q.top().pos;q.pop();for(int i=last[now];i;i=e[i].pre)

{int too=e[i].too;if(dist[too]>dist[now]+e[i].sum)

{

dist[too]=dist[now]+e[i].sum;

h[too]=h[now]+e[i].sum;

fq[too]=now;eg[too]=i;if(!v[too])

{

v[too]=1;

q.push((poi){dist[too],too});

}

}

}

v[now]=0;

}

}bool cmp(tjm a,tjm b){return a.len

{

tot=1;

read(n);read(m);for(int i=1;i<=m;i++)read(x),read(y),read(z),add(x,y,z),add(y,x,z);

spfa(1);for(int i=1;i<=n;i++)used[eg[i]]=used[eg[i]^1]=1;for(int i=1;i<=tot;i++)if(!used[i])

{

edge[++tot2].x=e[i].x;edge[tot2].y=e[i].too;

edge[tot2].len=e[i].sum+h[e[i].x]+h[e[i].too];

}

sort(edge+1,edge+1+tot2,cmp);for(int i=1;i<=n;i++)fa[i]=i;for(int i=1;i<=tot2;i++)

{int x=edge[i].x,y=edge[i].y,f1=gf(x),f2=gf(y),lastx=0,lasty=0;while(f1!=f2)

{if(h[f1]

{

v[x]=i;if(lastx)fa[lastx]=x;

}else if(lastx)fa[lastx]=f1;

lastx=f1;x=fq[lastx];f1=gf(x);

}

}for(int i=2;i<=n;i++)if(v[i])printf("%d\n",edge[v[i]].len-h[i]);else printf("-1\n");

}

View Code

bzoj1782: [Usaco2010 Feb]slowdown 慢慢游

其实就是求每个节点到根的路径上比自己小的节点有几个,BIT维护一下就行了。

好像网上题解有其他写法,等等去学习一下姿势

#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010;struct poi{inttoo,pre;}e[maxn];intn,m,x,y,z,tot;inta[maxn],p[maxn],ans[maxn],last[maxn],v[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}int lowbit(int x){return x&-x;}void update(int x,int delta){for(;x<=n;x+=lowbit(x))a[x]+=delta;}int sum(int x){int ret=0;for(;x;x-=lowbit(x))ret+=a[x];returnret;}void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}void dfs(int x,intfa)

{

ans[p[x]]=sum(p[x]-1);

update(p[x],1);for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa)

dfs(e[i].too,x);

update(p[x],-1);

}intmain()

{

read(n);for(int i=1;i

dfs(1,0);for(int i=1;i<=n;i++)printf("%d\n",ans[i]);return 0;

}

View Code

bzoj1571: [Usaco2009 Open]滑雪课Ski

挺显然的一个DP

f[i][j]表示时间i,能力值为j最多滑几次

预处理出mind[i]表示能力值为i滑一次雪的最短时间,ke[i][j]表示时间i结束,能力值达到j的课程开始的时间。

f[i][j]=max(f[i-1][j],f[i-mind[j]][j]+1,f[ke[i][j]][k]]);

最后一个可以开个数组g[i][j]记录max(f[i][1~j])来优化。

#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=10010;intn,x,y,z,tot,ans,t,s,m[maxn],l[maxn],a[maxn],c[maxn],d[maxn];int f[maxn][110],g[maxn][110],mind[maxn],ke[maxn][110];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(t);read(s);read(n);for(int i=1;i<=s;i++)

read(m[i]),read(l[i]),read(a[i]),ke[m[i]+l[i]][a[i]]=m[i];for(int i=1;i<=n;i++)read(c[i]),read(d[i]);for(int i=1;i<=100;i++)mind[i]=10001;for(int i=1;i<=100;i++)for(int j=1;j<=n;j++)if(c[j]<=i)mind[i]=min(mind[i],d[j]);

memset(f,-32,sizeof(f));

memset(g,-32,sizeof(g));

f[0][1]=g[0][1]=0;for(int i=1;i<=t;i++)

{for(int j=1;j<=10;j++)

{

f[i][j]=f[i-1][j];if(i>=mind[j])f[i][j]=max(f[i][j],f[i-mind[j]][j]+1);

f[i][j]=max(f[i][j],g[ke[i][j]][j]);

g[i][j]=max(g[i][j-1],f[i][j]);

}

}int ans=0;for(int i=1;i<=100;i++)ans=max(ans,f[t][i]);

printf("%d\n",ans);return 0;

}

View Code

bzoj1715: [Usaco2006 Dec]Wormholes 虫洞

spfa判负环。

傻了,输出NO没过行WA了好几次,输样例的时候看不出来。

#include#include#include#include

using namespacestd;struct zs{int dis,pre,too;}e[10000];inti,now,n,m,front,rear,x,y,z,tot,T,w;int h[51000],last[510],dis[510],ru[510];bool v[510];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}int spfa(intx)

{

memset(dis,50,(n+1)<<2);memset(v,0,sizeof(v));memset(ru,0,sizeof(ru));

dis[x]=0;front=0;rear=1;h[1]=x;v[x]=1;while(front!=rear)

{

now=h[++front];if(front==50000)front=-1;for(int i=last[now],to=e[i].too;i;i=e[i].pre,to=e[i].too)if(dis[to]>dis[now]+e[i].dis)

{

dis[to]=dis[now]+e[i].dis;if(!v[to])

{

h[++rear]=to;if(rear==50000)rear=-1;

v[to]=1;ru[to]++;if(ru[to]>233)return 1;

}

}

v[now]=0;

}return 0;

}void add(int x,int y,intz)

{

e[++tot].too=y;e[tot].dis=z;e[tot].pre=last[x];last[x]=tot;

}intmain()

{

read(T);while(T--)

{

tot=0;memset(last,0,sizeof(last));

read(n);read(m);read(w);for(int i=1;i<=m;i++)

read(x),read(y),read(z),add(x,y,z),add(y,x,z);for(int i=1;i<=w;i++)

read(x),read(y),read(z),add(x,y,-z);if(spfa(1))printf("YES\n");else printf("NO\n");

}return 0;

}

View Code

bzoj1596: [Usaco2008 Jan]电话网络

树形DP

dp[i][0]为i被覆盖,i不建塔

dp[i][1]为i建塔

dp[i][2]为i不被覆盖,i不建塔

一开始inf开太大GG了呜呜

#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=100000000;struct poi{inttoo,pre;}e[maxn];intn,m,x,y,z,tot;int dp[maxn][3],last[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}void dfs(int x,intfa)

{

dp[x][0]=inf;dp[x][1]=1;dp[x][2]=0;int sum=0;for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa)

{

dfs(e[i].too,x);

dp[x][1]+=min(dp[e[i].too][0],min(dp[e[i].too][1],dp[e[i].too][2]));

dp[x][2]+=min(dp[e[i].too][0],dp[e[i].too][1]);

sum+=min(dp[e[i].too][0],dp[e[i].too][1]);

}for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa)

dp[x][0]=min(dp[x][0],dp[e[i].too][1]-min(dp[e[i].too][0],dp[e[i].too][1])+sum);

}intmain()

{

read(n);for(int i=1;i

read(x),read(y),add(x,y),add(y,x);

dfs(1,0);

printf("%d",min(dp[1][0],dp[1][1]));return 0;

}

View Code

bzoj1770: [Usaco2009 Nov]lights 燈

meet in the middle

直接用Claris题解啦!

好像还能写高斯消元,那明天就学高斯消元吧嘿嘿嘿  UPD:不学了好难啊

又又又又又又叕叕叕叕叕叕交成老代码WA了好多次啊淦

好激心,对着能AC的代码找了大概有1h+找不出错

#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1000000000;

mapcnt;intn,m,x,y,half,ans;

ll f[233],state;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void dfs1(int x,ll st,intt)

{if(x==half)

{int &cntt=cnt[st];if(!cntt)cntt=t;else cntt=min(cntt,t);return;

}

dfs1(x+1,st,t);dfs1(x+1,st^f[x],t+1);

}void dfs2(int x,ll st,intt)

{if(x==(n-half))

{int &cntt=cnt[state^st];if(cntt)ans=min(ans,cntt+t-1);return;

}

dfs2(x+1,st,t);dfs2(x+1,st^f[x+half],t+1);

}intmain()

{

read(n);read(m);

half=n/2;state=(1ll<

{

read(x);read(y);

x--;y--;

f[x]|=1ll<

f[y]|=1ll<

}for(int i=0;i

ans=inf;

dfs1(0,0,1);dfs2(0,0,0);

printf("%d\n",ans);return 0;

}

View Code

bzoj1691: [Usaco2007 Dec]挑剔的美食家

贪心,用splay维护。把牛和牧草都按新鲜程度从大到小排序,枚举牛,把新鲜程度大于牛要求的都加进splay,找到牛要求的价格-1的后继,加入答案。

感觉splay的删除操作写的还是有点丑,下次再改改。

#include#include#include#include#include

#define which(x) (son[fa[x]][1]==x)

#define ll long long

using namespacestd;const int maxn=500010;struct poi{intcost,fresh;}a[maxn],b[maxn];const int extar[2]={2147483647,-2147483647};int fa[maxn],cnt[maxn],son[maxn][3],val[maxn],data[maxn];introot,x,y,n,m,j,tot,xiugai;

ll ans;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.fresh>b.fresh;}void rotate(intx)

{int f=fa[x];bool k=which(x);

son[f][k]=son[x][!k];son[x][!k]=f;son[fa[f]][which(f)]=x;if(son[f][k])fa[son[f][k]]=f;fa[x]=fa[f];fa[f]=x;

cnt[x]=cnt[f];

cnt[f]=cnt[son[f][0]]+cnt[son[f][1]]+val[f];

}void splay(int x,intg)

{while(fa[x]!=g)

{int f=fa[x];if(fa[f]==g)

{

rotate(x);break;

}if(which(x)^which(f))rotate(x);elserotate(f);

rotate(x);

}if(!g)root=x;

}int search(int x,inty)

{if(data[x]>y&&son[x][0])return search(son[x][0],y);if(data[x]

}int ext(int x,intw)

{int k=search(x,extar[w]);

splay(k,0);returndata[k];

}int succ(intx)

{int k=search(root,x);

splay(k,0);if(data[k]>x)returndata[k];return ext(son[k][1],1);

}void insert(int &x,int w,intf)

{if(!x)

{

x=++tot;

cnt[x]=val[x]=1;

data[x]=w;

fa[x]=f;

xiugai=tot;return;

}if(data[x]==w)val[x]++,xiugai=x;if(data[x]w)insert(son[x][0],w,x);

cnt[x]++;

}void del(intw)

{int k=search(root,w);

splay(k,0);if(data[k]==w)

{if(val[k]>1)val[k]--,cnt[k]--;else

if(!son[k][0])

{

root=son[k][1];

fa[root]=fa[k]=son[k][1]=cnt[k]=val[k]=data[k]=0;

}else{

fa[son[k][0]]=0;ext(son[k][0],0);

son[root][1]=son[k][1];if(son[k][1])fa[son[k][1]]=root;

cnt[root]+=cnt[son[k][1]];

fa[k]=son[k][0]=son[k][1]=data[k]=val[k]=cnt[k]=0;

}

}

}intmain()

{

read(n);read(m);if(n>m)

{

printf("-1\n");return 0;

}for(int i=1;i<=n;i++)read(a[i].cost),read(a[i].fresh);for(int i=1;i<=m;i++)read(b[i].cost),read(b[i].fresh);

sort(a+1,a+1+n,cmp);sort(b+1,b+1+m,cmp);

j=1;for(int i=1;i<=n;i++)

{for(;b[j].fresh>=a[i].fresh&&j<=m;j++)

{

insert(root,b[j].cost,0);

splay(xiugai,0);

}int now=succ(a[i].cost-1);if(now)ans+=now;else{

printf("-1\n");return 0;

}

del(now);

}

printf("%lld\n",ans);return 0;

}

View Code

bzoj1668: [Usaco2006 Oct]Cow Pie Treasures 馅饼里的财富

经典DP

#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=110;intn,m,x,y,z,tot;intf[maxn][maxn],map[maxn][maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(m);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)

read(map[i][j]);

memset(f,-0x7f,sizeof(f));

f[0][0]=0;for(int j=1;j<=m;j++)for(int i=1;i<=n;i++)

f[i][j]=max(f[i+1][j-1],max(f[i][j-1],f[i-1][j-1]))+map[i][j];

printf("%d\n",f[n][m]);return 0;

}

View Code

bzoj1593: [Usaco2008 Feb]Hotel 旅馆

线段树维护左边,中间,最大值。

查询时按 左 中 右的顺序查就可以保证最左边了

#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{int l,r,m,tag;}a[maxn*4];intn,m,x,y,z,tot;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void build(int x,int l,intr)

{

a[x].l=a[x].r=a[x].m=r-l+1;if(l==r)return;int mid=(l+r)>>1;

build(x<<1,l,mid);build(x<<1|1,mid+1,r);

}void pushup(int x,int l,intr)

{int mid=(l+r)>>1;

a[x].l=a[x<<1].l;a[x].r=a[x<<1|1].r;if(a[x<<1].l==(mid-l+1))a[x].l+=a[x<<1|1].l;if(a[x<<1|1].r==(r-mid))a[x].r+=a[x<<1].r;

a[x].m=max(a[x<<1].r+a[x<<1|1].l,max(a[x<<1].m,a[x<<1|1].m));

}void pushdown(int x,int l,intr)

{if(a[x].tag==1)

{int mid=(l+r)>>1;

a[x<<1].l=a[x<<1].r=a[x<<1].m=mid-l+1;a[x<<1].tag=1;

a[x<<1|1].l=a[x<<1|1].r=a[x<<1|1].m=r-mid;a[x<<1|1].tag=1;

}if(a[x].tag==2)

{

a[x<<1].l=a[x<<1].r=a[x<<1].m=0;a[x<<1].tag=2;

a[x<<1|1].l=a[x<<1|1].r=a[x<<1|1].m=0;a[x<<1|1].tag=2;

}

a[x].tag=0;

}void change(int x,int l,int r,int cl,int cr,intdelta)

{if(cl<=l&&r<=cr)

{

a[x].tag=delta;if(delta==1)a[x].l=a[x].r=a[x].m=r-l+1;else a[x].l=a[x].r=a[x].m=0;

}else{

pushdown(x,l,r);int mid=(l+r)>>1;if(cl<=mid)change(x<<1,l,mid,cl,cr,delta);if(cr>mid)change(x<<1|1,mid+1,r,cl,cr,delta);

pushup(x,l,r);

}

}int find(int x,int l,int r,intlen)

{

pushdown(x,l,r);if(l==r)returnl;int mid=(l+r)>>1;if(a[x<<1].m>=len)return find(x<<1,l,mid,len);if(a[x<<1].r+a[x<<1|1].l>=len)return mid-a[x<<1].r+1;return find(x<<1|1,mid+1,r,len);

}intmain()

{

read(n);read(m);

build(1,1,n);for(int i=1;i<=m;i++)

{

read(x);if(x==1)

{

read(y);if(a[x].m>=y)

{int l=find(1,1,n,y);

printf("%d\n",l);

change(1,1,n,l,l+y-1,2);

}else printf("0\n");

}if(x==2)

{

read(y);read(z);

change(1,1,n,y,y+z-1,1);

}

}return 0;

}

View Code

bzoj1697: [Usaco2007 Feb]Cow Sorting牛排序

置换群

两种方法中选更优的一种:(循环节总权值:sum,循环节大小:len,循环节中最小值:minai,数组中最小值:mina)

①每个循环节中最小值将其他移回原位。代价:sum+(len-2)*minai

②整个数组的最小值移进循环节帮循环节最小值将其他移回原位。代价:sum+(len+1)*mina+minai

#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010;struct poi{intsum,next;}a[maxn];intn,m,x,y,z,tot,mina,minai,j,k,ans;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.sum

{

read(n);for(int i=1;i<=n;i++)read(a[i].sum),a[i].next=i;

sort(a+1,a+1+n,cmp);

mina=a[1].sum;for(int i=1;i<=n;i++)if(a[i].next!=-1)

{

j=a[i].next;minai=a[i].sum;k=1;

a[i].next=-1;while(j!=i)

{

k++;

ans+=a[j].sum;int t=a[j].next;

a[j].next=-1;

j=t;

}

ans+=min((k-1)*minai,2*minai+(k+1)*mina);

}

printf("%d\n",ans);return 0;

}

View Code

bzoj1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居

曼哈顿距离|x1-y1|+|x2-y2|有四种情况

(x1-y1-(x2-y2))  (x1-y1-(y2-x2))  (y1-x1-(x2-y2))  (y1-x1-(y2-x2))

那我们陵X=x+y,Y=x-y,那两个点的曼哈顿距离为max(|X1-Y1|,|Y1-Y2|),也就是切比雪夫距离。

按X排序,保证队头队尾X的差<=c,加入新元素时用set找到(用splay处理重复元素有点麻烦,学习了一波set)前驱后继,如果前驱或后继的y和新加入元素的y差值<=c,就用并查集把新元素和前驱或后继连起来。

set用法见代码。find找到set中元素,lowerbound找到第一个大于等于它的元素,其实是不一样的,find找不到会返回end()。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010;const ll inf=1e10;intn,m,x,y,z,tot,ans,ans2,c,now;intfa[maxn],cnt[maxn];struct poi{ll x,y;intpos;}a[maxn],hj,qq;

multisetb;set::iterator it;bool operator

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}bool cmp(poi a,poi b){return a.x

{

x=gf(x);y=gf(y);if(x!=y)

{

fa[x]=y;

ans--;

}

}intmain()

{

read(n);read(c);for(int i=1;i<=n;i++)fa[i]=i;for(int i=1;i<=n;i++)

{

read(x);read(y);ans=n;

a[i].x=x+y;a[i].y=x-y;a[i].pos=i;

}

sort(a+1,a+1+n,cmp);

b.insert((poi){0,inf,0});b.insert((poi){0,-inf,0});

now=1;b.insert(a[1]);for(int i=2;i<=n;i++)

{while(a[i].x-a[now].x>c)b.erase(b.find(a[now++]));

it=b.lower_bound(a[i]);

hj=*it;qq=*--it;if(hj.y-a[i].y<=c)link(hj.pos,a[i].pos);if(a[i].y-qq.y<=c)link(qq.pos,a[i].pos);

b.insert(a[i]);

}for(int i=1;i<=n;i++)cnt[gf(i)]++;for(int i=1;i<=n;i++)ans2=max(ans2,cnt[i]);

printf("%d %d\n",ans,ans2);return 0;

}

View Code

bzoj1589: [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果

基环树找环+DP

#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,m,x,y,z,tot,j,top;intf[maxn],v[maxn],next[maxn],st[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);for(int i=1;i<=n;i++)read(next[i]);for(int i=1;i<=n;i++)if(!v[i])

{int top=0;for(j=i;!v[j];j=next[j])st[++top]=j,v[j]=i;if(v[j]==i)

{int cnt=1;for(;st[top-cnt+1]!=j;cnt++);for(int k=1;k<=cnt;k++)f[st[top-k+1]]=cnt;

top-=cnt;

}int cnt=0;while(top)f[st[top--]]=f[j]+(++cnt);

}for(int i=1;i<=n;i++)printf("%d\n",f[i]);return 0;

}

View Code

bzoj1574: [Usaco2009 Jan]地震损坏Damage

一开始看成最少损坏几个了,想了好久QAQ

最少几个不能去显然把不能去的几个周围一圈全部搞坏就行了,然后再dfs一遍找出一共几个不能回到1点就行了

#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{inttoo,pre;}e[maxn];intn,m,x,y,z,c,ans,tot;intmap[maxn],v[maxn],last[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}void dfs(intx)

{

ans--;v[x]=1;for(int i=last[x];i;i=e[i].pre)if(!v[e[i].too])dfs(e[i].too);

}intmain()

{

read(n);read(m);read(c);ans=n;for(int i=1;i<=m;i++)read(x),read(y),add(x,y),add(y,x);for(int i=1;i<=c;i++)

{

read(x);

v[x]=1;for(int j=last[x];j;j=e[j].pre)

v[e[j].too]=1;

}

dfs(1);

printf("%d\n",ans);return 0;

}

View Code

bzoj1707: [Usaco2007 Nov]tanning分配防晒霜

一开始只会网络流,感觉会TLE,不会写QAQ

#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{intx,y;}a[maxn];intn,m,x,y,z,tot,ans,spf[maxn],num[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.y

{

read(n);read(m);for(int i=1;i<=n;i++)read(a[i].x),read(a[i].y);

sort(a+1,a+1+n,cmp);for(int i=1;i<=m;i++)read(spf[i]),read(num[i]);

spf[0]=inf;for(int i=1;i<=n;i++)

{int mnj=0;for(int j=1;j<=m;j++)if(num[j])if(a[i].x<=spf[j]&&spf[j]<=a[i].y)if(spf[mnj]>spf[j])mnj=j;if(mnj)ans++,num[mnj]--;

}

printf("%d\n",ans);return 0;

}

View Code

bzoj1709: [Usaco2007 Oct]Super Paintball超级弹珠

直接记录。。。左上到右下是x-y+n,右上到左下是x+y-1,注意可能站在对手的位置射....

没删调试输出交上去WA了一次QAQ

#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=510,inf=1e9;intn,k,x,y,z,tot,ans;introw[maxn],col[maxn],lt[maxn],rt[maxn],map[maxn][maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(k);for(int i=1;i<=k;i++)

{

read(x);read(y);map[x][y]++;

row[x]++;col[y]++;lt[x-y+n]++;rt[x+y-1]++;

}for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(row[i]+col[j]+lt[i-j+n]+rt[i+j-1]-3*map[i][j]==k)ans++;

printf("%d\n",ans);return 0;

}

View Code

bzoj1706: [usaco2007 Nov]relays 奶牛接力跑

之前写过题解

#include#include#include#include

#define ll long long

using namespacestd;const int maxn=210;structpoi{ll mtx[maxn][maxn];}f,g;

ll n,m,s,t,tot,x,y,z;int v[1010];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void floyd(poi &a,poi b)

{

poi c;memset(c.mtx,0x3f,sizeof(c.mtx));for(int k=1;k<=tot;k++)for(int i=1;i<=tot;i++)for(int j=1;j<=tot;j++)

c.mtx[i][j]=min(c.mtx[i][j],a.mtx[i][k]+b.mtx[k][j]);

memcpy(a.mtx,c.mtx,sizeof(c.mtx));

}void ksm(intn)

{while(n)

{if(n&1)floyd(g,f);

floyd(f,f);

n>>=1;

}

}intmain()

{

read(n);read(m);read(s);read(t);

memset(f.mtx,0x3f,sizeof(f.mtx));for(int i=1;i<=m;i++)

{

read(z);read(x);read(y);if(!v[x])v[x]=++tot;if(!v[y])v[y]=++tot;

f.mtx[v[x]][v[y]]=min(f.mtx[v[x]][v[y]],z);

f.mtx[v[y]][v[x]]=min(f.mtx[v[y]][v[x]],z);

}

memset(g.mtx,0x3f,sizeof(g.mtx));for(int i=1;i<=tot;i++)g.mtx[i][i]=0;

ksm(n);

printf("%lld\n",g.mtx[v[s]][v[t]]);return 0;

}

View Code

bzoj1753: [Usaco2005 qua]Who's in the Middle

...直接排序

#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,m,x,y,z,tot;inta[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);for(int i=1;i<=n;i++)read(a[i]);

sort(a+1,a+1+n);

printf("%d\n",a[(n+1)>>1]);return 0;

}

View Code

bzoj1584: [Usaco2009 Mar]Cleaning Up 打扫卫生

有趣的DP...不会写(躺。感觉自己思维每次只能碰到正解的一部分,却达不到最关键的点,只想到了不同数个数的平方一定要小于长度,却没有根据这个推出不同数个数不能超过sqrt(n),虽然是显而易见的...(其实感觉跟不确定这题到底是不是DP有关,因为看数据范围就觉得像根号,但是从没见过带根号的DP...

f[i]=min(f[b[j]]+j*j)(1≤j*j≤n)

b[j]表示b[j]+1~i的出现次数为j。维护的话记录下每个a[i]最晚出现次数pre[a[i]],如果pre[a[i]]并没有出现在b[j]+1~i也就是pre[a[i]]<=b[j]的话,这一段的不同数个数就要增加(cnt[j]++),如果cnt[j]>j的话就必须从b[j]+1一直向右删,删到第一个在这一段里只出现一次的数,这可以用pre来判断。

总的时间复杂度O(nsqrt(n))

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,m,x,y,z,tot,k;inta[maxn],b[maxn],pre[maxn],cnt[maxn];

ll f[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(m);for(int i=1;i<=n;i++)read(a[i]);

memset(pre,-1,sizeof(pre));

memset(f,0x7f,sizeof(f));

f[0]=0;for(int i=1;i<=n;i++)

{for(int j=1;j*j<=n;j++)if(pre[a[i]]<=b[j])

{

cnt[j]++;if(cnt[j]>j)

{for(k=b[j]+1;k

 
 

b[j]=k;cnt[j]--;

}

}for(int j=1;j*j<=n;j++)

f[i]=min(f[i],f[b[j]]+j*j);

pre[a[i]]=i;

}

printf("%lld\n",f[n]);return 0;

}

View Code

bzoj1754: [Usaco2005 qua]Bull Math

高精度乘法,WA了5次,调了1h,身败名裂QAQ

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=510,inf=1e9;intlena,lenb,lenc;inta[maxn],b[maxn],c[maxn];char s1[500],s2[500];intmain()

{

scanf("%s%s",s1,s2);

lena=strlen(s1);lenb=strlen(s2);for(int i=0;i

{int x=0;for(int j=1;j<=lenb;j++)

{

x=a[i]*b[j]+x+c[i+j-1];

c[i+j-1]=x%10;

x/=10;

}

c[i+lenb]=x;

}

lenc=lena+lenb;while((!c[lenc])&&lenc>1)lenc--;for(int i=lenc;i;i--)printf("%d",c[i]);

printf("\n");return 0;

}

View Code

bzoj1828: [Usaco2010 Mar]balloc 农场分配

贪心,右端点第一关键字升序,左端点第二关键字降序,一个一个能取就取,正确性自己脑洞一下就知道了

感觉现在线段树挺熟悉的了,10min敲完 1A

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{int min,delta;}a[maxn*4];struct tjm{intx,y;}v[maxn];intn,m,x,y,z,tot,mn,ans;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(tjm a,tjm b){return a.y==b.y?a.x>b.x:a.y

{if(l==r)return;

a[x<<1].delta+=a[x].delta;a[x<<1|1].delta+=a[x].delta;

a[x<<1].min+=a[x].delta;a[x<<1|1].min+=a[x].delta;

a[x].delta=0;

}void build(int x,int l,intr)

{if(l==r)read(a[x].min);else{int mid=(l+r)>>1;

build(x<<1,l,mid);

build(x<<1|1,mid+1,r);

pushup(x,l,r);

}

}void update(int x,int l,int r,int wl,int wr,intdelta)

{if(wl<=l&&r<=wr)a[x].delta+=delta,a[x].min+=delta;else{

pushdown(x,l,r);int mid=(l+r)>>1;if(wl<=mid)update(x<<1,l,mid,wl,wr,delta);if(wr>mid)update(x<<1|1,mid+1,r,wl,wr,delta);

pushup(x,l,r);

}

}int query(int x,int l,int r,int wl,intwr)

{if(wl<=l&&r<=wr)returna[x].min;else{

pushdown(x,l,r);int mid=(l+r)>>1,ans=inf;if(wl<=mid)ans=min(ans,query(x<<1,l,mid,wl,wr));if(wr>mid)ans=min(ans,query(x<<1|1,mid+1,r,wl,wr));returnans;

}

}intmain()

{

read(n);read(m);

build(1,1,n);for(int i=1;i<=m;i++)read(v[i].x),read(v[i].y);

sort(v+1,v+1+m,cmp);for(int i=1;i<=m;i++)

{

mn=query(1,1,n,v[i].x,v[i].y);if(mn)ans++,update(1,1,n,v[i].x,v[i].y,-1);

}

printf("%d\n",ans);return 0;

}

View Code

bzoj1710: [Usaco2007 Open]Cheappal 廉价回文

添加和删除一样,然后就是经典DP了。f[l][r]表示把[l,r]改为回文的最小代价,则有:

f[l][r]=min(f[l+1][r]+cost[s[l]],f[l][r-1]+cost[s[r]];

if(s[l]==s[r])f[l][r]=min(f[l][r],f[l+1][r-1]);

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=2010,inf=1e9;intn,m,x,y,z,tot;intf[maxn][maxn],cost[maxn];char s[maxn],ch[2];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(m);

scanf("%s",s+1);for(int i=1;i<=n;i++)

{

scanf("%s",ch);read(x);read(y);

cost[(int)ch[0]]=min(x,y);

}for(int i=1;i

{

f[l][l+i]=min(f[l+1][l+i]+cost[(int)s[l]],f[l][l+i-1]+cost[(int)s[l+i]]);if(s[l]==s[l+i])f[l][l+i]=min(f[l][l+i],f[l+1][l+i-1]);

}

printf("%d\n",f[1][m]);return 0;

}

View Code

bzoj1598: [Usaco2008 Mar]牛跑步

K短路,启发式搜索A*模板。

f(n)=g(n)+h(n),g为n到起点实际距离,h为n到终点最短距离,所以先跑一遍最短路,从n点开始A*,1进队k次后得到k个答案。

#include#include#include#include#include

using namespacestd;const int maxn=500010,inf=1e9;struct poi{intdis,pos;};struct zs{inttoo,sum,pre;}e[maxn],e2[maxn];

priority_queueq;bool operatorb.dis;}intn,m,k,x,y,z,tot;intlast[maxn],last2[maxn],dist[maxn],tim[maxn],ans[maxn];boolv[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add1(int x,int y,int z){e[++tot].too=y;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}void add2(int x,int y,int z){e2[++tot].too=y;e2[tot].sum=z;e2[tot].pre=last2[x];last2[x]=tot;}voidspfa()

{for(int i=1;i<=n;i++)dist[i]=inf;

dist[1]=0;q.push((poi){0,1});while(!q.empty())

{int now=q.top().pos;q.pop();for(int i=last[now],too=e[i].too;i;i=e[i].pre,too=e[i].too)if(dist[too]>dist[now]+e[i].sum)

{

dist[too]=dist[now]+e[i].sum;if(!v[too])

{

v[too]=1;

q.push((poi){dist[too],too});

}

}

v[now]=0;

}

}voidastar()

{

q.push((poi){dist[n],n});while(!q.empty())

{

poi top=q.top();int now=top.pos,dis=top.dis;q.pop();

tim[now]++;if(now==1)ans[tim[now]]=dis;if(tim[now]<=k)for(int i=last2[now],too=e2[i].too;i;i=e2[i].pre,too=e2[i].too)

q.push((poi){dis-dist[now]+e2[i].sum+dist[too],too});

}

}intmain()

{

read(n);read(m);read(k);for(int i=1;i<=m;i++)

{

read(x);read(y);read(z);

add1(y,x,z);add2(x,y,z);

}

spfa();

astar();for(int i=1;i<=k;i++)if(ans[i])printf("%d\n",ans[i]);else printf("-1\n");return 0;

}

View Code

bzoj2060: [Usaco2010 Nov]Visiting Cows 拜访奶牛

树形DP f[x][1]表示x选  f[x][0]表示x不选

f[x][1]=sigma(f[son[]][0]);

f[x][0]=max(sigma(max(f[son[]][0],f[son[]][1]))-max(f[son[i]][0],f[son[i]][1])+f[son[i]][1]);

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{inttoo,pre;}e[maxn];intn,m,x,y,z,tot;int f[maxn][2],last[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}void dp(int x,intfa)

{

f[x][1]=1;int sum=0;for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa)

{

dp(e[i].too,x);

f[x][1]+=f[e[i].too][0];

sum+=max(f[e[i].too][1],f[e[i].too][0]);

}for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa)f[x][0]=max(f[x][0],sum-max(f[e[i].too][1],f[e[i].too][0])+f[e[i].too][1]);

}intmain()

{

read(n);for(int i=1;i

dp(1,0);

printf("%d\n",max(f[1][0],f[1][1]));return 0;

}

View Code

bzoj1741: [Usaco2005 nov]Asteroids 穿越小行星群

对于一个小行星(x,y),如果x不打y一定要打,于是x连y做二分图最大匹配就行了,或者可以理解成最小割

#include#include#include#include

using namespacestd;struct poi{int too,pre;}e[2000001];int n,m,x,y,t,tot,ans,num,lin[1000001],last[1000001],v[1000001];void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool dfs(intx)

{for(int i=last[x],too=e[i].too;i;i=e[i].pre,too=e[i].too)if(v[too]!=t)

{

v[too]=t;if((!lin[too])||dfs(lin[too]))

{

lin[too]=x;return 1;

}

}return 0;

}intmain()

{

read(n);read(m);for(int i=1;i<=m;i++)read(x),read(y),add(x,y);for(int i=1;i<=n;i++)

{++t;if(dfs(i))ans++;

}

printf("%d\n",ans);

}

View Code

bzoj1703: [Usaco2007 Mar]Ranking the Cows 奶牛排名

传递闭包+bitset优化

#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=1010,inf=1e9;intn,m,x,y,ans;

bitseta[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(m);for(int i=1;i<=m;i++)read(x),read(y),a[x][y]=1;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(a[j][i])a[j]|=a[i];

ans=0;for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)if(!(a[i][j]||a[j][i]))ans++;

printf("%d\n",ans);return 0;

}

View Code

bzoj1578: [Usaco2009 Feb]Stock Market 股票市场

没见过的DP,居然可以用前一天的DP值来当容量(躺(智商太低想不到系列。

显然某一天卖股票只可能卖一种,也就是之前肯定只买一种来卖,这个自己yy一下就知道了。

f[i]表示第i天的最大收益,然后用前一天的DP值来做完全背包就行了。至于为什么用前一天的,因为用之前的和用前一天的其实是一样的,相当于之前买的在前一天卖了再买。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,m,x,y,z,tot,d;int f[20],gp[100][100],g[20][700010];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(d);read(m);for(int i=1;i<=n;i++)for(int j=1;j<=d;j++)

read(gp[j][i]);

f[1]=m;for(int i=2;i<=d;i++)

{for(int j=1;j<=n;j++)for(int k=gp[i-1][j];k<=f[i-1];k++)

g[i][k]=max(g[i][k-gp[i-1][j]]+gp[i][j]-gp[i-1][j],g[i][k]);

f[i]=g[i][f[i-1]]+f[i-1];

}

printf("%d\n",f[d]);return 0;

}

View Code

bzoj1702: [Usaco2007 Mar]Gold Balanced Lineup 平衡的队列

转2进制后前缀和,前缀和的每位都减去第一位,如果有两个前缀和 i 和 j 相同的话,那么i+1~j这一段的k种颜色出现次数一样多。哈希之后用map,我的写法怎么这么奇葩233

很好证明,∵ b1-a1==b2-a2==b3-a3 ∴  b1-b1-(a1-a1)==b2-b1-(a2-a1)==b3-b1-(a3-a1)==0

#include#include#include#include#include

#define ull unsigned long long

using namespacestd;const int maxn=100010,inf=1e9;

mapa;intn,k,now,ans,x;int digit[maxn][50];void read(int &k)

{

k=0;int f=1;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}int find(intpos)

{

ull sum=0;for(int i=2;i<=k;i++)sum=sum*233+1ull*digit[pos][i];if(!a[sum]&&sum)a[sum]=pos;returna[sum];

}intmain()

{

read(n);read(k);for(int i=1;i<=n;i++)

{

read(x);int now=0;for(;x;x>>=1)digit[i][++now]=x&1;for(int j=1;j<=k;j++)digit[i][j]+=digit[i-1][j];

}for(int i=1;i<=n;i++)

{for(int j=2;j<=k;j++)digit[i][j]-=digit[i][1];

ans=max(ans,i-find(i));

}

printf("%d\n",ans);

}

View Code

bzoj1734: [Usaco2005 feb]Aggressive cows 愤怒的牛

二分最小值最大化

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,c,x,y,z,tot,l,r,mid;inta[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}boolcheck()

{int cnt=0,pre=-inf;for(int i=1;i<=n;i++)

{if(a[i]-pre>=mid)cnt++,pre=a[i];if(cnt==c)return 1;

}return 0;

}intmain()

{

read(n);read(c);for(int i=1;i<=n;i++)read(a[i]);

sort(a+1,a+1+n);

l=0;r=1e9;while(l

{

mid=(l+r+1)>>1;if(check())l=mid;else r=mid-1;

}

printf("%d\n",l);return 0;

}

View Code

bzoj1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害

最小割。把每个点拆成俩,连起来容量为1,有report的点容量就为inf,原图边按二分图加进去,容量inf。S连1,report的点连T,跑最大流。

1是不能割的,所以拆点后容量也是inf,查了好久TAT

#include#include#include#include

using namespacestd;const int inf=1000000000,maxn=60010;struct poi{int too,pre,cf;}e[500010];intn,m,tot,ans,x,y,z,front,rear,sum,p;inth[maxn],v[maxn],last[maxn],dis[maxn],cur[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,intz)

{

e[++tot].too=y;e[tot].cf=z;e[tot].pre=last[x];last[x]=tot;

e[++tot].too=x;e[tot].pre=last[y];last[y]=tot;

}boolbfs()

{for(int i=0;i<=sum;i++)v[i]=0,dis[i]=-1;

dis[0]=0;v[0]=1;h[1]=0;front=0;rear=1;while(front!=rear)

{int now=h[++front];if(front==maxn)front=-1;for(int i=last[now];i;i=e[i].pre)

{int too=e[i].too;if((!v[too])&&e[i].cf)

{

dis[too]=dis[now]+1;if(too==sum)return 1;

v[too]=1;h[++rear]=too;if(rear==maxn)rear=-1;

}

}

}return 0;

}int dfs(int x,intf)

{int flow=0,tmp;if(x==sum)returnf;for(int &i=cur[x];i;i=e[i].pre)

{int too=e[i].too;if(dis[too]==dis[x]+1&&e[i].cf)

{

tmp=dfs(too,min(f-flow,e[i].cf));

e[i].cf-=tmp;e[i^1].cf+=tmp;flow+=tmp;if(f==flow)returnf;

}

}returnflow;

}voiddinic()

{while(bfs())

{for(int i=0;i<=sum;i++)cur[i]=last[i];

ans+=dfs(0,inf);

}

}intmain()

{

tot=1;

read(p);read(m);read(n);sum=p*2+1;

add(0,1,inf);add(1,1+p,inf);for(int i=2;i<=p;i++)add(i,i+p,1);for(int i=1;i<=m;i++)

read(x),read(y),add(x+p,y,inf),add(y+p,x,inf);for(int i=1;i<=n;i++)

read(x),add(x,x+p,inf),add(x+p,sum,inf);

dinic();

printf("%d\n",ans);return 0;

}

View Code

----------------------------------------BZOJ 100题纪念----------------------------------------

bzoj1704: [Usaco2007 Mar]Face The Right Way 自动转身机

O(n)枚举k,O(n)扫一遍判断。从左到右,遇见反着的就转过来,前面的保证已经转好了就不要再动了,一直往后扫就行。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,m,x,y,z,tot,ansk,ans,tim,now;inta[maxn],v[maxn];char ch[2];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);for(int i=1;i<=n;i++)

{

scanf("%s",ch);if(ch[0]=='B')a[i]=1;

}

ans=inf;for(int i=1;i<=n;i++)

{

tim=0;now=0;for(int j=1;j<=n-i+1;j++)

{if(v[j]==i)now^=1;if(a[j]^now)tim++,now^=1,v[j+i]=i;

}bool flag=0;for(int j=n-i+2;j<=n;j++)

{if(v[j]==i)now^=1;if(a[j]^now)

{

flag=1;break;

}

}if(!flag)if(tim

}

printf("%d %d\n",ansk,ans);return 0;

}

View Code

bzoj2199: [Usaco2011 Jan]奶牛议会

网上题解都不tarjan缩点的。。。一缩就跑到#26了

因为是求所有解中的,不能拓扑后倒序了,只能一个议案一个议案地枚举,判断Y和N是否可以,如果Y和N都行就是?了。

今天发现自己写了两年的tarjan一直是错的,怎么还能过那么多题QAQ

#include#include#include#include

using namespacestd;const int maxn=500010;struct poi{intx,too,pre;}e[maxn],e2[maxn];intn,m,t,tot,tot2,tott,top,color;intdfn[maxn],low[maxn],col[maxn],last[maxn],last2[maxn],v[maxn],st[maxn],lack[maxn];charans[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intreadd()

{int x;read(x);char c=getchar();while(c!='Y'&&c!='N')c=getchar();if(c=='Y')return (x<<1)^1;return x<<1;

}void add(int x,int y){e[++tot].too=y;e[tot].x=x;e[tot].pre=last[x];last[x]=tot;}void add2(int x,int y){e2[++tot2].too=y;e2[tot2].x=x;e2[tot2].pre=last2[x];last2[x]=tot2;}void dfs(intx)

{

v[x]=t;for(int i=last2[x];i;i=e2[i].pre)if(v[e2[i].too]!=t)dfs(e2[i].too);

}bool check(intx)

{

t++;dfs(x);for(int i=1;i<=n;i++)if(v[col[(i<<1)^1]]==t&&v[col[i<<1]]==t)return 0;return 1;

}void tarjan(intx)

{

dfn[x]=low[x]=++tott;st[++top]=x;lack[x]=top;for(int i=last[x];i;i=e[i].pre)if(!dfn[e[i].too])tarjan(e[i].too),low[x]=min(low[x],low[e[i].too]);else if(!col[e[i].too])low[x]=min(low[x],dfn[e[i].too]);if(dfn[x]==low[x])

{

color++;for(;top>=lack[x];top--)col[st[top]]=color;

}

}void dfss(intx)

{

v[x]=1;for(int i=last[x];i;i=e[i].pre)if(!v[e[i].too])dfss(e[i].too);

}intmain()

{

read(n);read(m);for(int i=1;i<=m;i++)

{int x=readd(),y=readd();

add(x^1,y);add(y^1,x);

}for(int i=2;i<=((n<<1)^1);i++)if(!dfn[i])tarjan(i);for(int i=1;i<=tot;i++)if(col[e[i].x]!=col[e[i].too])add2(col[e[i].x],col[e[i].too]);for(int i=1;i<=n;i++)

{if(col[(i<<1)^1]==col[i<<1]){puts("IMPOSSIBLE");return 0;}int x=check(col[(i<<1)^1]),y=check(col[i<<1]);if(!(x||y)){puts("IMPOSSIBLE");return 0;}else if(x&&y)ans[i]='?';else if(x)ans[i]='Y';else if(y)ans[i]='N';

}for(int i=1;i<=n;i++)putchar(ans[i]);

}

View Code

bzoj1718: [Usaco2006 Jan] Redundant Paths 分离的路径

边双连通分量缩点后求出叶子数,(leaf+1)/2为答案,易证,自己脑补

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{intx,too,pre;}e[maxn],e2[maxn];intn,m,x,y,z,tot,tot2,leaf,tott,top,color;intcol[maxn],dfn[maxn],low[maxn],st[maxn],lack[maxn],last[maxn],chu[maxn],last2[maxn],v[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].x=x;e[tot].too=y;e[tot].pre=last[x];last[x]=tot;}void add2(int x,int y){e2[++tot2].x=x;e2[tot2].too=y;e2[tot2].pre=last2[x];last2[x]=tot2;}void tarjan(int x,intfa)

{

dfn[x]=low[x]=++tott;st[++top]=x;lack[x]=top;for(int i=last[x],too=e[i].too;i;i=e[i].pre,too=e[i].too)if(too!=fa)

{if(!dfn[too])tarjan(too,x),low[x]=min(low[x],low[too]);else if(!col[too])low[x]=min(low[x],dfn[too]);

}if(dfn[x]==low[x])for(color++;top>=lack[x];top--)col[st[top]]=color,add2(color,st[top]);

}intmain()

{

read(n);read(m);for(int i=1;i<=m;i++)read(x),read(y),add(x,y),add(y,x);for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0);for(int k=1;k<=color;k++)for(int j=last2[k];j;j=e2[j].pre)for(int i=last[e2[j].too];i;i=e[i].pre)if(v[col[e[i].too]]!=k&&(col[e[i].too]!=k))chu[k]++,v[col[e[i].too]]=k;for(int i=1;i<=color;i++)if(chu[i]==1)leaf++;

printf("%d\n",(leaf+1)/2);return 0;

}

View Code

bzoj1700: [Usaco2007 Jan]Problem Solving 解题

DP。f[i][j]表示解决i到j道题的最少天数。

如果某天付完尾款还能在付首付就有 f[j][i]=min(f[k][j-1]+1)

不然就  f[j][i]=min(f[k][j-1]+2)

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=310,inf=1e9;intn,m,x,y,z,tot;intf[maxn][maxn],suma[maxn],sumb[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(m);read(n);for(int i=1;i<=n;i++)read(suma[i]),read(sumb[i]);for(int i=1;i<=n;i++)suma[i]+=suma[i-1],sumb[i]+=sumb[i-1];

memset(f,0x3f,sizeof(f));f[0][0]=2;for(int i=1;i<=n;i++)for(int j=1;j<=i;j++)for(int k=0;k

{if(m>=(sumb[j-1]-sumb[k-1])&&m>=(suma[i]-suma[j-1])&&m>=(sumb[i]-sumb[j-1]))

f[j][i]=min(f[j][i],f[k][j-1]+2);if(m>=(sumb[j-1]-sumb[k-1]+suma[i]-suma[j-1])&&m>=(sumb[i]-sumb[j-1]))

f[j][i]=min(f[j][i],f[k][j-1]+1);

}int ans=inf;for(int i=1;i<=n;i++)ans=min(ans,f[i][n]);

printf("%d\n",ans);return 0;

}

View Code

bzoj1755: [Usaco2005 qua]Bank Interest

。。。。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;doubler,m,y;void read(double &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(r);read(m);read(y);for(int i=1;i<=y;i++)

m=m*(1+r/100);

printf("%d\n",(int)floor(m));return 0;

}

View Code

bzoj1731: [Usaco2005 dec]Layout 排队布局

差分约束系统。

求最大值的话先化成x-y<=c的形式(c为常数),y往x连边权值为c跑最短路。

求最小值的话先化成x-y>=c的形式(c为常数),y往x连边权值为c跑最长路。

小于或大于要化成小于等于或大于等于

负环则无解。dist[n]==inf说明对n无限制。

理解:x-y<=c化成x<=c+y的形式,类似最短路中的松弛操作(dist[too]>dist[now]+e[i].dis),最长路同理。最短路为最大值是因为同小取小,最长路最小值是因为同大取大。

#include#include#include#include

using namespacestd;const int maxn=500010,inf=1e9;struct poi{inttoo,pre,sum;}e[maxn];intn,ml,md,x,y,z,front,rear,tot;intdist[maxn],h[maxn],v[maxn],last[maxn],tim[maxn];boolflag;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,int z){e[++tot].too=y;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}voidspfa()

{for(int i=1;i<=n;i++)dist[i]=inf;

dist[1]=0;v[1]=1;front=rear=0;h[++rear]=1;while(front!=rear)

{int now=h[++front];if(front==maxn)front=-1;for(int i=last[now],too=e[i].too;i;i=e[i].pre,too=e[i].too)if(dist[too]>dist[now]+e[i].sum)

{

dist[too]=dist[now]+e[i].sum;if(!v[too])

{if(tim[too]>233){printf("-1");flag=1;return;}

tim[too]++;v[too]=1;h[++rear]=too;if(rear==maxn)rear=-1;

}

}

v[now]=0;

}

}intmain()

{

read(n);read(ml);read(md);for(int i=2;i<=n;i++)add(i,i-1,0);for(int i=1;i<=ml;i++)read(x),read(y),read(z),add(x,y,z);for(int i=1;i<=md;i++)read(x),read(y),read(z),add(y,x,-z);

spfa();if(flag)return 0;if(dist[n]==inf)printf("-2");else printf("%d\n",dist[n]);return 0;

}

View Code

bzoj1705: [Usaco2007 Nov]Telephone Wire 架设电话线

f[i][j]前 i 个柱子,第 i 个高度为 j 的最小代价

f[i][j] = f[i-1][k] + c*(j-k) + (h[i]-j)^2

f[i][j] = f[i-1][k] - c*k  + c*j + h[i]^2 - 2*h[i]*j + j^2;

可以发现k和j无关,所以可以把时间复杂度降低到O(n*100)

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=100010,inf=2147483647;intn,c,x,y,z,mn,ans,tot;int h[maxn],f[maxn][110];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(c);for(int i=1;i<=n;i++)read(h[i]);

memset(f,0x7f,sizeof(f));for(int i=1;i<=100;i++)f[1][i]=(h[1]-i)*(h[1]-i);for(int i=2;i<=n;i++)

{

mn=inf;for(int j=h[i-1];j

{

mn=min(mn,f[i-1][j]-c*j);

f[i][j]=min(f[i][j],mn-2*h[i]*j+j*j+c*j+h[i]*h[i]);

}

mn=inf;for(int j=100;j>=h[i];j--)

{if(j>=h[i-1])mn=min(mn,f[i-1][j]+c*j);

f[i][j]=min(f[i][j],mn-2*h[i]*j+j*j-c*j+h[i]*h[i]);

}

}

ans=inf;for(int i=1;i<=100;i++)ans=min(ans,f[n][i]);

printf("%d\n",ans);return 0;

}

View Code

bzoj1575: [Usaco2009 Jan]气象牛Baric

f[i][j]前 i 个数据,选了 j 个的最小误差

预处理出st[i] , mid[i][j] , ed[i]表示 i 为开头的误差,选 i 和 j 中间的误差,i 为结尾的误差。

if(j==1)f[i][j] = st[i];

else f[i][j] = f[k][j-1] + mid[k][i];

最后找最小值的时候再把ed[i]加上就行。

一开始没在数据最小前提下找最小误差WA了两次好气啊

#include#include#include#include

#define ll long long

using namespacestd;const int maxn=110,inf=1e9;intn,e;

ll f[maxn][maxn],ans2;intst[maxn],mid[maxn][maxn],ed[maxn],a[maxn],ans;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(e);for(int i=1;i<=n;i++)read(a[i]);for(int i=0;i<=n;i++)

{for(int j=1;j

mid[i][j]+=abs(2*a[k]-a[i]-a[j]);for(int j=i+1;j<=n;j++)ed[i]+=2*abs(a[i]-a[j]);

}

memset(f,32,sizeof(f));f[0][0]=0;for(int i=1;i<=n;i++)for(int j=1;j<=i;j++)if(j==1)f[i][j]=st[i];else for(int k=0;k

ans=ans2=inf;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(f[j][i]+ed[j]<=e)if(ans>=i)ans=i,ans2=min(ans2,f[j][i]+ed[j]);

printf("%d %lld\n",ans,ans2);

}

View Code

bzoj1783: [Usaco2010 Jan]Taking Turns

博弈论DP...

f[i]表示先手取i,先手能取得的最大收益。g[i]表示先手取i,后手能获得的最大收益。

后手显然每次取之前先手能取的最大收益,因为先手取完变后手。

因为先手是之前的后手,后手是之前的先手,所以先手之前取什么取决于后手,那么先手就只能取后手取的maxi的后手最大值+a[i]。

g[i] = f[maxi];

f[i] = g[maxi] + a[i];

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=700010,inf=1e9;intn,m,x,y,z,tot,maxi;inta[maxn];

ll f[maxn],g[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);for(int i=1;i<=n;i++)read(a[i]);

maxi=n+1;for(int i=n;i;i--)

{

g[i]=f[maxi];

f[i]=g[maxi]+a[i];if(f[i]>=f[maxi])maxi=i;

}

printf("%lld %lld\n",f[maxi],g[maxi]);return 0;

}

View Code

UPD:还有一种比较妙的做法是,维护X和Y分别表示当前的先手的最大收益和当前的后手的最大收益,实际上先手已经选过了,现在排到后手选,若是后手选了a[i]能大于等于当前的先手,也就是先手能找到一个更大的收益,那么就选,并且后手变先手。

用DP更好理解。f[i][0]表示先手,f[i][1]表示后手。两人都不选,f[i][0]=f[i+1][0],f[i][1]=f[i+1][1]。但是上次的后手可以变成这次的先手if(f[i+1][1]+a[i]>=f[i][0])f[i][0]=f[i+1][1]+a[i],同时上次先手变这次后手f[i][1]=f[i+1][0];

注意由于是倒推,应该找个先手的最大值,若后手取一个数没有比当前先手大而变成先手的话,显然先手并不会这么笨,还是取之前那个好

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=700010,inf=1e9;intn,a[maxn];

ll x,y;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);for(int i=1;i<=n;i++)read(a[i]);for(int i=n;i;i--)if(y+a[i]>=x)swap(x,y),x+=a[i];

printf("%lld %lld\n",x,y);return 0;

}

View Code

bzoj1774: [Usaco2009 Dec]Toll 过路费

floyd中间点按点权从小到大枚举,那i->k->j这条路径上点权最大的一定是 i j k 三者之一。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=310,inf=1e9;structpoi{ll c,pos;}a[maxn];

ll n,m,K,x,y,z;

ll f[maxn][maxn],g[maxn][maxn],cc[maxn];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.c

{

read(n);read(m);read(K);for(int i=1;i<=n;i++)read(a[i].c),a[i].pos=i,cc[i]=a[i].c;

sort(a+1,a+1+n,cmp);

memset(f,32,sizeof(f));memset(g,32,sizeof(g));for(int i=1;i<=m;i++)read(x),read(y),read(z),g[y][x]=g[x][y]=min(z,g[x][y]);for(int i=1;i<=n;i++)g[i][i]=0;for(int l=1;l<=n;l++)

{

ll k=a[l].pos,c=a[l].c;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)

{

g[i][j]=min(g[i][j],g[i][k]+g[k][j]);

f[i][j]=min(f[i][j],g[i][k]+g[k][j]+max(c,max(cc[i],cc[j])));

}

}for(int i=1;i<=K;i++)

{

read(x);read(y);

printf("%lld\n",f[x][y]);

}return 0;

}

View Code

bzoj1590: [Usaco2008 Dec]Secret Message 秘密信息

字典树记录一下就行。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,m,x,y,z,tot;int next[maxn][3],a[maxn],son[maxn],cnt[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void insert(intlen)

{int now=1;for(int i=1;i<=len;i++)

{if(!next[now][a[i]])next[now][a[i]]=++tot;

now=next[now][a[i]];

son[now]++;if(i==len)cnt[now]++;

}

}int find(intlen)

{int now=1,sum=0;for(int i=1;i<=len;i++)

{if(!next[now][a[i]])break;

now=next[now][a[i]];if(i==len)sum+=son[now];else sum+=cnt[now];

}returnsum;

}intmain()

{

tot=1;

read(n);read(m);for(int i=1;i<=n;i++)

{

read(x);for(int j=1;j<=x;j++)

read(a[j]);

insert(x);

}for(int i=1;i<=m;i++)

{

read(x);for(int j=1;j<=x;j++)

read(a[j]);

printf("%d\n",find(x));

}return 0;

}

View Code

bzoj1577: [Usaco2009 Feb]庙会捷运Fair Shuttle

贪心,能加就加,不能加踢出去最晚下车的。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct zs{inty,c,pre;}e[maxn];struct poi{inty,c;};

priority_queueq;bool operator

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,int z){e[++tot].y=y;e[tot].c=z;e[tot].pre=last[x];last[x]=tot;}intmain()

{

read(k);read(n);read(c);for(int i=1;i<=k;i++)

{

read(x);read(y);read(z);if(x==y)ans+=z;elseadd(x,y,z);

}for(int i=1;i<=n;i++)

{for(int j=last[i];j;j=e[j].pre)q.push((poi){e[j].y,e[j].c}),people+=e[j].c,xiache[e[j].y]+=e[j].c;

ans+=xiache[i];people-=xiache[i];while(people>c)

{

poi now=q.top();

people-=now.c;xiache[now.y]-=now.c;q.pop();if(people

}

}

printf("%d\n",ans);return 0;

}

View Code

bzoj1663: [Usaco2006 Open]赶集

按时间排序后DP f[i] = max ( f[i] , f[j]+1 ) t[j] + dis[j][i] <= t[i]

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=510,inf=1e9;struct poi{intt,pos;}a[maxn];intn,m,x,y,z,tot,ans;intf[maxn],dis[maxn][maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.t

{

read(n);for(int i=1;i<=n;i++)read(a[i].t),a[i].pos=i;

sort(a+1,a+1+n,cmp);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)read(dis[i][j]);for(int i=1;i<=n;i++)dis[0][i]=dis[1][i];for(int i=1;i<=n;i++)

{for(int j=0;j

{

f[i]=max(f[i],f[j]+1);

ans=max(ans,f[i]);

}

}

printf("%d\n",ans);return 0;

}

View Code

bzoj1775: [Usaco2009 Dec]Vidgame 电视游戏问题

自己瞎写了个DP居然过了...

f[i][j]表示前 i 个平台,预算为 j 的最大收益

f[i][j] = max( f[i][j] , max( f[i][k-gp[i]]+pv[j] , f[i-1][k-gp[i]]+pv[j] ) );

算 i 时 k 循环范围是  v-p[i]~gp[i] ,最后令f[i][k]=f[i][k-p[i]],相当于强制买了平台。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,m,x,y,z,tot,v;int f[55][100010],p[maxn],g[maxn],gp[maxn],pv[maxn],ans;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(v);for(int i=1;i<=n;i++)

{

read(p[i]);read(g[i]);for(int j=1;j<=g[i];j++)

{

read(gp[j]);read(pv[j]);for(int k=v-p[i];k>=gp[j];k--)

f[i][k]=max(f[i][k],max(f[i][k-gp[j]]+pv[j],f[i-1][k-gp[j]]+pv[j]));

}for(int k=v;k>=p[i];k--)f[i][k]=max(f[i-1][k],f[i][k-p[i]]);for(int k=p[i]-1;k>=0;k--)f[i][k]=f[i-1][k];

}for(int i=0;i<=v;i++)ans=max(ans,f[n][v]);

printf("%d\n",ans);return 0;

}

View Code

bzoj1583: [Usaco2009 Mar]Moon Mooing 哞哞叫

两个公式都是递增的,那么搞一个队列,记录下两个公式分别遍历到哪里,比较两个公式遍历到的元素再算一次公式的大小,把小的一个加入队列并把指针后移一位,这样可以保证一直最小。

#include#include#include#include

#define ll long long

using namespacestd;const int maxn=4000010;

ll n,c,num[10][10],now1,now2,ans[maxn],r;void read(ll &k)

{

k=0;int f=1;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(c);read(n);for(int i=1;i<=2;i++)for(int j=1;j<=3;j++)

read(num[i][j]);

ans[1]=c;int l1=1,l2=1;r=1;

now1=num[1][1]*c/num[1][3]+num[1][2];

now2=num[2][1]*c/num[2][3]+num[2][2];while(r

{if(now1

{if(now1!=ans[r])ans[++r]=now1;

now1=ans[++l1]*num[1][1]/num[1][3]+num[1][2];

}else{if(now2!=ans[r])ans[++r]=now2;

now2=ans[++l2]*num[2][1]/num[2][3]+num[2][2];

}

}

printf("%lld\n",ans[n]);

}

View Code

bzoj1716: [Usaco2006 Dec]The Fewest Coins 找零钱

对John做多重背包,店家做无限(完全?)背包,如果John给的钱超过n*vmax,那至少给了(n+1)个硬币,根据抽屉原理必有一种硬币有两颗,所以拿回来就行。。。网上题解说的vmax*vmax我不怎么懂QAQ

涨姿势,原来多重背包还能二进制优化O_O

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010;struct poi{intc,v;}a[maxn];intn,m,x,y,z,tot,t,N,t1,t2,vmax,ans,inf;intf[maxn],g[maxn],v[maxn],c[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.v

{

read(n);read(t);for(int i=1;i<=n;i++)read(v[i]),vmax=max(vmax,v[i]);for(int i=1;i<=n;i++)

{

read(c[i]);for(int j=1;j<=c[i];j<<=1)a[++N].c=j,a[N].v=v[i]*j,c[i]-=j;if(c[i])a[++N].c=c[i],a[N].v=c[i]*v[i];

}

sort(a+1,a+1+N,cmp);

t1=t+n*vmax;t2=n*vmax;while(N&&a[N].v>t1)N--;

memset(f,32,(t1+1)<<2);f[0]=0;inf=f[1];for(int i=1;i<=N;i++)

{for(int j=t1;j>=a[i].v;j--)

f[j]=min(f[j],f[j-a[i].v]+a[i].c);

}

memset(g,32,(t2+1)<<2);g[0]=0;for(int i=1;i<=n;i++)

{for(int j=v[i];j<=t2;j++)

g[j]=min(g[j],g[j-v[i]]+1);

}

ans=inf;for(int i=t;i<=t1;i++)ans=min(ans,f[i]+g[i-t]);if(ans==inf)printf("-1");else printf("%d\n",ans);return 0;

}

View Code

bzoj1742: [Usaco2005 nov]Grazing on the Run 边跑边吃草

好神的DP!居然计算未来的代价!虽然这样中间的状态就都全部是为最后的答案服务,本身是错误的了...

因为不可能路过草不吃,于是吃的一定是一段连续的区间。

f[i][j][0]表示吃了 i ~ j ,在 i 的代价,f[i][j][0]就是在 j 的代价。

f[i][j][0] = min ( f[i+1][j][0] + dis( i , i + 1) * ( n - ( j - i )) , f[i+1][j][1] + dis( i , j ) * ( n - ( j - i ) ));

之所以* ( n - ( j - i ))是因为走这段路的过程中其他草也会增加腐败度,计算了未来的代价,妙啊

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=1010,inf=1e9;intn,m,x,y,z,tot,ans,l,rc;int f[maxn][2],a[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(l);for(int i=1;i<=n;i++)read(a[i]);

sort(a+1,a+1+n);for(int i=1;a[i]<=l&&i<=n;i++)f[i][1]=f[i][0]=(l-a[i])*n,rc=i;for(int i=rc+1;i<=n;i++)f[i][1]=f[i][0]=(a[i]-l)*n;for(int i=1;i

{for(int j=1;j<=n;j++)

{

f[j][1]=min(f[j][1]+(a[j+i]-a[j+i-1])*(n-i),f[j][0]+(a[j+i]-a[j])*(n-i));

f[j][0]=min(f[j+1][0]+(a[j+1]-a[j])*(n-i),f[j+1][1]+(a[j+i]-a[j])*(n-i));

}

}

printf("%d\n",min(f[1][1],f[1][0]));return 0;

}

View Code

bzoj1594: [Usaco2008 Jan]猜数游戏

卡常卡的已经不知道这题怎么写了233,至少上了第一页QAQ  CZL#1 %%%

二分答案,区间权值降序排序后,用并查集check,具体方法是将某个区间[l,r]的所有数父亲变为l-1,如果r的父亲 < l说明这个区间被完全覆盖了。

矛盾的情况:①相同权值的区间没有交集②权值大的区间覆盖了权值小的区间的交集

判断相同权值有没有交集的话只要记录最大的左端点lmax和最小的右端点rmin,如果rmin

于是这个权值一定存在于[lmax,rmin]这个交集,看一下有没有被覆盖就行了。

因为权值相同的区间一定都有交集所以可以看成一个大区间把lmin到rmax全部指向lmin-1。

离散化的话如果两个区间的端点没有紧挨着(r1+1

像这种求被覆盖区间的都可以用并查集

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=1000010,inf=1e9;struct poi{intpos,sum;}b[maxn];intn,m,mid,lmax,lmin,rmax,rmin,now,last,rc,noww,l1,r1;int l[maxn],r[maxn],x[maxn],a[maxn*2],pos[maxn],fa[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.sum>b.sum;}int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}boolcheck()

{for(int i=1;i<=now;i++)fa[i]=i;

noww=1;while(b[noww].pos>mid)noww++;

lmax=lmin=pos[l[b[noww].pos]],rmax=rmin=pos[r[b[noww].pos]];

rc=1;last=noww;for(int i=noww+1;i<=m;i++)

{if(b[i].pos>mid)continue;

rc++;if(b[i].sum!=b[last].sum)

{if(gf(rmin)=lmin;j=fa[j])fa[gf(j)]=gf(j-1);

lmax=lmin=pos[l[b[i].pos]],rmax=rmin=pos[r[b[i].pos]];

}else{

lmax=max(lmax,pos[l[b[i].pos]]);lmin=min(lmin,pos[l[b[i].pos]]);

rmax=max(rmax,pos[r[b[i].pos]]);rmin=min(rmin,pos[r[b[i].pos]]);if(rmin

}if(rc==mid)break;

last=i;

}if(gf(rmin)

}intmain()

{

read(n);read(m);for(int i=1;i<=m;i++)read(l[i]),read(r[i]),read(x[i]);for(int i=1;i<=m;i++)a[i<<1]=l[i],a[(i<<1)-1]=r[i];

sort(a+1,a+1+(m<<1));

now=2;for(int i=1;i<=(m<<1);i++,now++)

{

pos[a[i]]=now;if(a[i]+1

}for(int i=1;i<=m;i++)b[i].sum=x[i],b[i].pos=i;

sort(b+1,b+1+m,cmp);

l1=1,r1=m;while(l1

{

mid=(l1+r1+1)>>1;if(check())l1=mid;else r1=mid-1;

}

printf("%d",l1==m?0:(l1+1));return 0;

}

View Code

bzoj1712: [Usaco2007 China]Summing Sums 加密

可以发现sum每次都*(n-1)(QAQ我怎么没发现),然后就可以矩阵快速幂了。

先把矩阵跑出来, 然后乘n次得到n个答案就行了。。。不需要每次都跑个矩阵出来(我傻逼吧

#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9,mod=98765431;struct poi{ll mtx[3][3];}map,g,c;

ll n,m,x,y,z,T,sum;

ll a[maxn];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void merge(poi &a,poi &b)

{

c.mtx[1][1]=c.mtx[1][2]=c.mtx[2][1]=c.mtx[2][2]=0;for(int i=1;i<=2;i++)for(int j=1;j<=2;j++)for(int k=1;k<=2;k++)

c.mtx[i][j]=(c.mtx[i][j]+a.mtx[i][k]*b.mtx[k][j])%mod;

a.mtx[1][1]=c.mtx[1][1];a.mtx[1][2]=c.mtx[1][2];

a.mtx[2][1]=c.mtx[2][1];a.mtx[2][2]=c.mtx[2][2];

}void qsm(intn)

{while(n)

{if(n&1)merge(map,g);

merge(g,g);

n>>=1;

}

}intmain()

{

read(n);read(T);for(int i=1;i<=n;i++)read(a[i]);for(int i=1;i<=n;i++)sum=(sum+a[i])%mod;

map.mtx[1][1]=map.mtx[2][2]=1;map.mtx[1][2]=map.mtx[2][1]=0;

g.mtx[1][1]=-1;g.mtx[1][2]=1;g.mtx[2][1]=0;g.mtx[2][2]=n-1;

qsm(T);for(int i=1;i<=n;i++)printf("%lld\n",(map.mtx[1][1]*a[i]+map.mtx[1][2]*sum)%mod);return 0;

}

View Code

bzoj1916: [Usaco2010 Open]冲浪

DP。f[i][j][1]表示第i个点,失控了j次,这一次会失控。f[i][j][0]表示第i个点,失控了j次,这一次不会失控。

会失控就找到最小的,不会失控就找最大的,两者取最小值就是至少能得到的。

f[i][j][1]=min(f[i][j][1],min(f[e[i].too][j-1][1],f[e[i].too][j-1][0])+e[i].sum);

f[i][j][0]=max(f[i][j][0],min(f[e[i].too][j][1],f[e[i].too][j][0])+e[i].sum);

看了题解才知道最后一维省略其实更好写,我好傻QAQ

f[i][j]=min(min(f[e[i].too][j-1]+e[i].sum),max(f[e[i].too][j]+e[i].sum))。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=50010,inf=1e9;struct poi{ll too,sum,pre;}e[maxn*10];

ll n,m,k,x,y,z,tot,ans;

ll f[maxn][20][2],last[maxn];boolv[maxn];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,int z){e[++tot].too=y;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}int min(int x,inty)

{if(x<0)returny;if(y<0)returnx;return x>y?y:x;

}void dfs(intx)

{if(x==n)return;for(int i=last[x],too=e[i].too;i;i=e[i].pre,too=e[i].too)if(!v[too])v[too]=1,dfs(too);for(int j=0;j<=k;j++)

{

f[x][j][1]=1ll*inf*10000;f[x][j][0]=-1ll*inf*10000;for(int i=last[x],too=e[i].too;i;i=e[i].pre,too=e[i].too)

{if(j)f[x][j][1]=min(f[x][j][1],min(f[too][j-1][1],f[too][j-1][0])+e[i].sum);

f[x][j][0]=max(f[x][j][0],min(f[too][j][1],f[too][j][0])+e[i].sum);

}

}

}intmain()

{

read(n);read(m);read(k);for(int i=1;i<=m;i++)read(x),read(y),read(z),add(x,y,z);

dfs(1);

ans=1ll*inf*10000;for(int i=0;i<=k;i++)

{

ans=min(ans,f[1][i][0]);

ans=min(ans,f[1][i][1]);

}

printf("%lld\n",ans);return 0;

}

View Code

bzoj2274: [Usaco2011 Feb]Generic Cow Protests

MDZZ为什么模数是1e9+9啊???不按常理出牌

卡了半天常数没快多少还丑了一堆...那还是不卡常好了

离散化一下前缀和就可以用BIT优化DP了

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9,mod=1e9+9;

ll n,x,N;

ll tree[maxn],a[maxn],b[maxn];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}int lowbit(ll x){return x&-x;}void add(ll x,ll y){for(;x<=N;x+=lowbit(x))tree[x]=tree[x]+y,(tree[x]>=mod)&&(tree[x]-=mod);}int find(ll x){ll sum=0;for(;x;x-=lowbit(x))sum=sum+tree[x],sum>=mod&&(sum-=mod);returnsum;}intmain()

{

read(n);for(int i=1;i<=n;i++)read(a[i]),a[i]+=a[i-1],b[++N]=a[i];N++;

sort(b+1,b+1+N);N=unique(b+1,b+1+N)-b-1;for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+N,a[i])-b;

x=lower_bound(b+1,b+1+N,0)-b;

add(x,1);for(int i=1;i<=n;i++)

{

x=find(a[i]);

x>=mod&&(x-=mod);

add(a[i],x);

}

printf("%lld\n",x);return 0;

}

View Code

bzoj2097: [Usaco2010 Dec]Exercise 奶牛健美操

二分+树形DP+贪心

把所有子树的最长长度排序,某棵子树如果最长长度超过mid就切,否则如果最长+次长超过mid就切最长。

#include#include#include#include#include

using namespacestd;const int maxn=500010,inf=1e9;struct poi{inttoo,pre;}e[maxn];intn,s,x,y,l,r,mid,tot,ans,cnt;inta[maxn],b[maxn],fir[maxn],last[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}bool dfs(int x,intfa)

{int cnt=0;for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa)if(!dfs(e[i].too,x))return 0;for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa)b[++cnt]=fir[e[i].too]+1;

sort(b+1,b+1+cnt);for(;cnt;cnt--)

{if(b[cnt]>mid)ans++;else if(b[cnt]+b[cnt-1]>mid)ans++;else break;if(ans>s)return 0;

}

fir[x]=b[cnt];return 1;

}intmain()

{

read(n);read(s);if(n==n-1){puts("0");return 0;}if(n==n-2){puts("1");return 0;}for(int i=1;i

l=0;r=n-1;while(l

{

ans=0;

mid=(l+r)>>1;if(dfs(1,0))r=mid;else l=mid+1;

}

printf("%d\n",l);

}

View Code

bzoj1735: [Usaco2005 jan]Muddy Fields 泥泞的牧场

同一行连通,同一列连通的行和列标同样的号,然后二分图最大匹配,同bzoj1741

#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=1010,inf=1e9,dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};struct poi{inttoo,pre;}e[maxn];intn,m,x,y,z,tot,rowcnt,clncnt,t,ans;intlast[maxn],lin[maxn],row[maxn][maxn],cln[maxn][maxn],vv[maxn];boolmap[maxn][maxn];chars[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}bool xyl(intx)

{for(int i=last[x];i;i=e[i].pre)if(vv[e[i].too]!=t)

{

vv[e[i].too]=t;if((!lin[e[i].too])||xyl(lin[e[i].too]))

{

lin[e[i].too]=x;return 1;

}

}return 0;

}intmain()

{

read(n);read(m);for(int i=1;i<=n;i++)

{

scanf("%s",s+1);for(int j=1;j<=m;j++)

map[i][j]=(s[j]=='*');

}for(int i=1;i<=n;i++)

{

rowcnt++;for(int j=1;j<=m;j++)if(!map[i][j])rowcnt++;else row[i][j]=rowcnt;

}for(int i=1;i<=m;i++)

{

clncnt++;for(int j=1;j<=n;j++)if(!map[j][i])clncnt++;else cln[j][i]=clncnt;

}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(map[i][j])

add(row[i][j],cln[i][j]);for(int i=1;i<=rowcnt;i++)t++,ans+=xyl(i);

printf("%d\n",ans);return 0;

}

View Code

bzoj1738: [Usaco2005 mar]Ombrophobic Bovines 发抖的牛

没输出-1 WA了一万次,很伤心

先跑floyed,二分答案,小于这个答案的边加入,跑最大流check

这种所有牛同时出发找最短时间的一般都是二分,一开始以为是总时间想写费用流才发现不对QAQ

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=10100;const ll inf=4223372036854775808;struct poi{ll too,pre,cf;}e[1000010];

ll n,m,tot,ans,x,y,z,front,rear,sum;

ll l,r,mid,cnt,mx;

ll h[maxn],v[maxn],last[maxn],dis[maxn],cur[maxn],a[maxn],b[maxn];

ll f[410][410];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,inty,ll z)

{

e[++tot].too=y;e[tot].cf=z;e[tot].pre=last[x];last[x]=tot;

e[++tot].too=x;e[tot].cf=0;e[tot].pre=last[y];last[y]=tot;

}boolbfs()

{for(int i=0;i<=sum;i++)v[i]=0,dis[i]=-1;

dis[0]=0;v[0]=1;h[1]=0;front=0;rear=1;while(front!=rear)

{int now=h[++front];if(front==maxn)front=-1;for(int i=last[now];i;i=e[i].pre)

{int too=e[i].too;if((!v[too])&&e[i].cf)

{

dis[too]=dis[now]+1;if(too==sum)return 1;

v[too]=1;h[++rear]=too;if(rear==maxn)rear=-1;

}

}

}return 0;

}int dfs(intx,ll f)

{int flow=0,tmp;if(x==sum)returnf;for(ll &i=cur[x];i;i=e[i].pre)

{int too=e[i].too;if(dis[too]==dis[x]+1&&e[i].cf)

{

tmp=dfs(too,min(f-flow,e[i].cf));

e[i].cf-=tmp;e[i^1].cf+=tmp;flow+=tmp;if(f==flow)returnf;

}

}returnflow;

}voiddinic()

{while(bfs())

{for(int i=0;i<=sum;i++)cur[i]=last[i];

ans+=dfs(0,inf);

}

}boolcheck()

{

memset(last,0,sizeof(last));memset(dis,0,sizeof(dis));tot=1;for(int i=1;i<=n;i++)add(0,i,a[i]),add(i,i+n,inf),add(i+n,sum,b[i]);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(f[i][j]<=mid)add(i,j+n,inf);

ans=0;

dinic();return ans==cnt;

}intmain()

{

tot=1;

read(n);read(m);sum=2*n+1;for(int i=1;i<=n;i++)read(a[i]),read(b[i]),cnt+=a[i];for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)f[i][j]=inf;for(int i=1;i<=n;i++)f[i][i]=0;for(int i=1;i<=m;i++)read(x),read(y),read(z),f[x][y]=min((ll)z,f[x][y]),f[y][x]=f[x][y],mx+=f[x][y];for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)

f[i][j]=min(f[i][j],f[i][k]+f[k][j]);

l=0;r=mx+1;while(l

{

mid=(l+r)>>1;if(check())r=mid;else l=mid+1;

}if(r==(mx+1)&&(!check()))printf("-1");else printf("%lld\n",l);return 0;

}

View Code

bzoj1740: [Usaco2005 mar]Yogurt factory 奶酪工厂

记录一下之前的费用最小值和现在比较就行了...之前被HR一眼秒过

#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;

ll n,s,c,y,mn,ans;void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')f=='-'&&(c=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(s);

mn=inf;for(int i=1;i<=n;i++)

{

read(c);read(y);

mn=min(mn+s,c);

ans+=mn*y;

}

printf("%lld\n",ans);

}

View Code

bzoj2099: [Usaco2010 Dec]Letter 恐吓信

不会SAM(躺

显然每次砍LCP就行。

先跑出A串的SA,这样就排好了每个后缀的字典序,于是在A串中二分找到B串的字典序位置 l,LCP一定是B串与sa[l]或sa[l+1]开始的后缀的LCP,然后logn求LCP就行了。

#include#include#include#include

#define ull unsigned long long

using namespacestd;const int maxn=100010;intn,m,p,ans,mm;intsum[maxn],rk[maxn],sa[maxn],trk[maxn],tsa[maxn];

ull hs1[maxn],hs2[maxn],mul[maxn];chars[maxn],s2[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}voidsuffix()

{for(int i=1;i<=n;i++)sum[s[i]]++;for(int i=1;i<=255;i++)sum[i]+=sum[i-1];for(int i=n;i;i--)sa[sum[s[i]]]=i,sum[s[i]]--;

rk[sa[1]]=1;p=1;for(int i=2;i<=n;i++)rk[sa[i]]=(s[sa[i]]!=s[sa[i-1]])?++p:p;

m=p;int j=1;while(m

{

memcpy(trk,rk,sizeof(rk));memset(sum,0,sizeof(sum));p=0;for(int i=n-j+1;i<=n;i++)tsa[++p]=i;for(int i=1;i<=n;i++)if(sa[i]>j)tsa[++p]=sa[i]-j;for(int i=1;i<=n;i++)rk[i]=trk[tsa[i]],sum[rk[i]]++;for(int i=2;i<=m;i++)sum[i]+=sum[i-1];for(int i=n;i;i--)sa[sum[rk[i]]]=tsa[i],sum[rk[i]]--;

rk[sa[1]]=1;p=1;for(int i=2;i<=n;i++)rk[sa[i]]=(trk[sa[i]]!=trk[sa[i-1]]||trk[sa[i]+j]!=trk[sa[i-1]+j])?++p:p;

m=p;j*=2;

}

}int lcp(int a,intb)

{int l=0,r=min(n-a+1,mm-b+1);while(l

{int mid=(l+r+1)>>1;

ull hsa=hs1[a]-hs1[a+mid]*mul[mid],hsb=hs2[b]-hs2[b+mid]*mul[mid];if(hsa!=hsb)r=mid-1;else l=mid;

}returnl;

}intmain()

{

read(n);read(mm);for(int i=1;i<=n;i++)for(s[i]=getchar();s[i]'Z';s[i]=getchar());

suffix();

mul[0]=1;for(int i=1;i<=n;i++)mul[i]=mul[i-1]*27;for(int i=n;i;i--)hs1[i]=hs1[i+1]*27+1ull*(s[i]-'A');for(int i=1;i<=mm;i++)for(s2[i]=getchar();s2[i]'Z';s2[i]=getchar());for(int i=mm;i;i--)hs2[i]=hs2[i+1]*27+1ull*(s2[i]-'A');for(int i=1;i<=mm;)

{int l=1,r=n;while(l

{int mid=(l+r+1)>>1;int len=lcp(sa[mid],i);if(s[sa[mid]+len]

}

i+=max(lcp(sa[l],i),lcp(sa[l+1],i));

ans++;

}

printf("%d\n",ans);

}

View Code

bzoj3408: [Usaco2009 Oct]Heat Wave 热浪

太年轻了一直不敢下手,就是个最短路而已= =

同样年轻的LLQ大佬

不贴代码了这博客要炸了

bzoj1744: [Usaco2005 oct]Skiing 奶牛滑雪

好强的题!正着来不行,倒着跑就可以了。从n,m到1,1,走过哪条边就给原来后面的距离除以这条边对速度的影响。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=1010,dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};intn,m,x,y,z,tot,v0,nx,ny;int h[maxn*1000][2],front,rear,ht[maxn][maxn];

ll mi[maxn];doubledist[maxn][maxn],fumi[maxn];boolv[maxn][maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}double get(int x,inty)

{if(x>y)return mi[x-y];return fumi[y-x];

}void spfa(int x,inty)

{double inf=1<<30;inf*=inf;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)dist[i][j]=inf;

h[1][1]=x;h[1][2]=y;front=0;rear=1;v[x][y]=1;dist[x][y]=0.0;while(front!=rear)

{

nx=h[++front][1];ny=h[front][2];if(front==maxn*1000)front=-1;for(int i=0;i<4;i++)

{int xx=nx+dx[i],yy=ny+dy[i];if(xx<1||xx>n||yy<1||yy>m)continue;if(dist[xx][yy]>dist[nx][ny]/get(ht[xx][yy],ht[nx][ny])+1.0)

{

dist[xx][yy]=dist[nx][ny]/get(ht[xx][yy],ht[nx][ny])+1.0;if(!v[xx][yy])

{

v[xx][yy]=1;h[++rear][1]=xx;h[rear][2]=yy;if(rear==maxn*1000)rear=-1;

}

}

}

v[nx][ny]=0;

}

}intmain()

{

read(v0);read(n);read(m);

mi[0]=1;fumi[0]=1.0;for(int i=1;i<=50;i++)mi[i]=mi[i-1]*2;for(int i=1;i<=50;i++)fumi[i]=fumi[i-1]/2;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)

read(ht[i][j]);

spfa(n,m);

printf("%.2lf\n",dist[1][1]/v0);return 0;

}

View Code

bzoj1752: [Usaco2005 qua]Til the Cows Come Home

同上上题...nm看反WA了4次T_T

bzoj1733: [Usaco2005 feb]Secret Milking Machine 神秘的挤奶机

二分,长度<=mid就加入,网络流check

看样子很多人的网络流都没加当前弧优化?加了之后就上第一页了...

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{inttoo,pre,cf;}e[maxn];intn,m,tot,ans,front,rear,mid,t,l,r;int h[maxn],v[maxn],last[210],dis[maxn],cur[maxn],x[maxn],y[maxn],z[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,intz)

{

e[++tot].too=y;e[tot].cf=z;e[tot].pre=last[x];last[x]=tot;

e[++tot].too=x;e[tot].cf=0;e[tot].pre=last[y];last[y]=tot;

}boolbfs()

{for(int i=1;i<=n;i++)v[i]=0,dis[i]=-1;

dis[1]=0;v[1]=1;h[1]=1;front=0;rear=1;while(front!=rear)

{int now=h[++front];if(front==maxn)front=-1;for(int i=last[now];i;i=e[i].pre)

{int too=e[i].too;if((!v[too])&&e[i].cf)

{

dis[too]=dis[now]+1;if(too==n)return 1;

v[too]=1;h[++rear]=too;if(rear==maxn)rear=-1;

}

}

}return 0;

}int dfs(int x,intf)

{int flow=0,tmp;if(x==n)returnf;for(int &i=cur[x];i;i=e[i].pre)

{int too=e[i].too;if(dis[too]==dis[x]+1&&e[i].cf)

{

tmp=dfs(too,min(f-flow,e[i].cf));

e[i].cf-=tmp;e[i^1].cf+=tmp;flow+=tmp;if(f==flow)returnf;

}

}returnflow;

}voiddinic()

{while(bfs())

{for(int i=1;i<=n;i++)cur[i]=last[i];

ans+=dfs(1,inf);

}

}boolcheck()

{

tot=1;memset(last,0,sizeof(last));for(int i=1;i<=m;i++)if(z[i]<=mid)

{

add(x[i],y[i],1);

add(y[i],x[i],1);

}

ans=0;

dinic();return ans>=t;

}intmain()

{

read(n);read(m);read(t);l=inf;r=-inf;for(int i=1;i<=m;i++)read(x[i]),read(y[i]),read(z[i]),l=min(l,z[i]),r=max(r,z[i]);while(l

{

mid=(l+r)>>1;if(check())r=mid;else l=mid+1;

}

printf("%d\n",l);return 0;

}

View Code

bzoj2196: [Usaco2011 Mar]Brownie Slicing

二分,再套个二分检验。。。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=510,inf=1e9;

ll n,m,x,y,z,tot,cnt,A,B,l,r,mid,mid2,now;

ll a[maxn][maxn],sum[maxn][maxn];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}boolcheckcheck()

{int ans=0,last=1;for(int i=1;i<=m;i++)if(sum[mid2][i]-sum[now-1][i]-sum[mid2][last-1]+sum[now-1][last-1]>=mid)

{

last=i+1;

ans++;if(ans==B)return 1;

}return 0;

}boolcheck()

{

now=1;for(int i=1;i<=A;i++)

{int l=now,r=n;while(l

{

mid2=(l+r)>>1;if(checkcheck())r=mid2;else l=mid2+1;

}if(i==A)return mid2=(l+r)>>1,checkcheck();

now=l+1;if(now>n)return 0;

}return 0;

}intmain()

{

read(n);read(m);read(A);read(B);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)

read(a[i][j]),cnt+=a[i][j],sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];

l=0;r=cnt/A/B;while(l

{

mid=(l+r+1)>>1;if(check())l=mid;else r=mid-1;

}

printf("%lld\n",l);return 0;

}

View Code

bzoj1739: [Usaco2005 mar]Space Elevator 太空电梯

做n次多重背包

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{inth,limit,c;}a[maxn];intn,m,x,y,z,tot,ans;intf[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.limit

{

read(n);for(int i=1;i<=n;i++)read(a[i].h),read(a[i].limit),read(a[i].c);

sort(a+1,a+1+n,cmp);for(int i=1;i<=n;i++)for(int j=a[i].limit;j>=a[i].h;j--)for(int k=1;k<=a[i].c;k++)

{if(k*a[i].h>j)break;

f[j]=max(f[j],f[j-k*a[i].h]+k*a[i].h);

}for(int i=1;i<=a[n].limit;i++)ans=max(f[i],ans);

printf("%d\n",ans);return 0;

}

View Code

bzoj2501: [usaco2010 Oct]Soda Machine

差分

#include#include#include#include#include

using namespacestd;const int maxn=500010;struct poi{intsum,pos;}a[maxn];intn,now,ans,cnt;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.sum

{

read(n);for(int i=1;i<=n;i++)read(a[++cnt].sum),a[cnt].pos=1,read(a[++cnt].sum),a[cnt].sum++,a[cnt].pos=-1;

sort(a+1,a+1+cnt,cmp);for(int i=1;i<=cnt;i++)

{

now+=a[i].pos;if(a[i].sum!=a[i+1].sum)

ans=max(ans,now);

}

printf("%d\n",ans);

}

View Code

bzoj2590: [Usaco2012 Feb]Cow Coupons

网上题解大部分是错的。。。包括黄学长的也被我hack了。还有一个博客大小写反了= =,但是代码是对的

首先肯定选k个优惠券最小的,如果不够选直接输出。如果还有多余的钱的话,比较一下(已买的里面原价与优惠价的最小差价+没买的里面的最小优惠价)和(没买的里面的最小原价),选一个小的。第一个实际上相当于把优惠卷花钱赎回来。。。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;structpoi{ll sum,i;}qq1,qq2,qq3;structzs{ll p,c;}a[maxn];

priority_queueq1,q2,q3;bool operatorb.sum;}

ll n,m,k,x,y,z,tot,cost,ans;boolv[maxn];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(zs a,zs b){return a.c

{

read(n);read(k);read(m);for(int i=1;i<=n;i++)read(a[i].p),read(a[i].c);

sort(a+1,a+1+n,cmp);for(int i=1;i<=k;i++)

{

cost+=a[i].c;if(cost>m){printf("%d\n",i-1);return 0;}

}for(int i=1;i<=k;i++)q1.push((poi){a[i].p-a[i].c,i});for(int i=k+1;i<=n;i++)q2.push((poi){a[i].c,i}),q3.push((poi){a[i].p,i});

ans=k;v[0]=1;while(cost

{if(!q1.empty())qq1=q1.top(),q1.pop();else qq1.sum=inf;if(!q2.empty())for(qq2=q2.top(),q2.pop();v[qq2.i]&&(!q2.empty());q2.pop())qq2=q2.top();else qq2.sum=inf,qq2.i=0;if(v[qq2.i])qq2.sum=inf;if(!q3.empty())for(qq3=q3.top(),q3.pop();v[qq3.i]&&(!q3.empty());q3.pop())qq3=q3.top();else qq3.sum=inf,qq3.i=0;if(v[qq3.i])qq3.sum=inf;if(qq1.sum+qq2.sum>qq3.sum)

{

cost+=qq3.sum;if(qq1.sum!=inf)q1.push((poi){qq1.sum,qq1.i});if(qq2.sum!=inf)q2.push((poi){qq2.sum,qq2.i});

}else{

cost+=qq1.sum+qq2.sum;if(qq3.sum!=inf)q3.push((poi){qq3.sum,qq3.i});

}if(cost<=m)ans++;if(ans==n)break;

}

printf("%lld\n",ans);return 0;

}

View Code

bzoj1986: [USACO2004 Dec] Dividing the Path 划区灌溉

傻逼题调了半天。。怎么最近老是不能1A啊。。。总是出奇奇怪怪的错误

f[i]表示0~i被灌溉的最少喷灌器。

f[i]=min(f[j])+1;(i-2*B<=j<=I-2*A)

如果i在(l[i],r[i])中,f[i]=inf;

单调队列优化即可

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=1000010,inf=1e9;intn,m,x,y,z,tot,l,r,L,A,B,now;intf[maxn],q[maxn],sum[maxn],v[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(L);read(A);read(B);for(int i=1;i<=n;i++)

{

read(x);read(y);if(x+1==y)continue;

sum[x+1]++;sum[y]--;

}

l=1;r=0;for(int i=1;i<=L;i++)

{

now+=sum[i];v[i]=now;if(i&1)continue;if((!v[i-2*A])&&i-2*A>=0)

{while(l<=r&&f[q[r]]>f[i-2*A])r--;

q[++r]=i-2*A;

}while(l<=r&&(i-q[l]>2*B))l++;

f[i]=(l>r)?inf:f[q[l]]+1;

}

printf("%d\n",f[L]

}

View Code

bzoj1722: [Usaco2006 Mar] Milk Team Select 产奶比赛

早上打hihocoder暴力分都没拿满好惨啊QAQ

这破题还调了好久,我好傻逼

一眼树形DP。f[i][j][0/1] 有 j 对亲属关系,节点 i 选/不选。

对每个子树做多重背包就行了。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=510,inf=1e9;struct poi{int too,pre;}e[maxn*100];intn,m,x,y,z,tot,X;int f[maxn][maxn][2],a[maxn],last[maxn],size[maxn],son[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}void dfs(intx)

{

f[x][0][0]=0;f[x][0][1]=a[x];for(int i=last[x];i;i=e[i].pre)dfs(e[i].too),size[x]+=size[e[i].too]+1,son[x]++;for(int i=last[x];i;i=e[i].pre)for(int j=size[x];j>=0;j--)

{for(int k=0;k<=min(j,size[e[i].too]);k++)

{if(j<=size[x]-son[x])f[x][j][0]=max(f[x][j][0],f[x][j-k][0]+max(f[e[i].too][k][0],f[e[i].too][k][1]));

f[x][j][1]=max(f[x][j][1],f[x][j-k][1]+max(f[e[i].too][k][0],k!=0?f[e[i].too][k-1][1]:-inf));

}if(j>size[e[i].too])f[x][j][1]=max(f[x][j][1],f[x][j-size[e[i].too]-1][1]+f[e[i].too][size[e[i].too]][1]);

}//for(int i=0;i<=size[x];i++)printf("x:%d i:%d fxi0:%d fxi1:%d\n",x,i,f[x][i][0],f[x][i][1]);

}intmain()

{

read(n);read(X);for(int i=1;i<=n;i++)

{

read(a[i]);read(y);if(y)add(y,i);else add(0,i);

}

memset(f,-32,sizeof(f));

dfs(0);//printf("%d %d\n",f[1][0][0],f[1][0][1]);

for(int i=n-1;i>=0;i--)if(f[0][i][0]>=X){printf("%d\n",i);return 0;}

printf("-1");return 0;

}

View Code

bzoj2059: [Usaco2010 Nov]Buying Feed 购买饲料

MDZZ忘记自己开的是long long是8字节。。。初始化老是小了

简单DP。f[i][j]表示前i个商店,买j吨饲料的最小代价,单调队列优化。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;structpoi{ll x,f,c;}a[maxn];

ll n,m,tot,k,e,l,r;

ll ans,dp[510][10010];

ll q[maxn];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return a.x

{

read(k);read(e);read(n);for(int i=1;i<=n;i++)read(a[i].x),read(a[i].f),read(a[i].c);

sort(a+1,a+1+n,cmp);

memset(dp[0],0x7f,(k+1)<<3);dp[0][0]=0;for(int i=1;i<=n;i++)

{

l=1;r=0;for(int j=0;j<=k;j++)

{

dp[i][j]=1ll*inf*10000;while(l<=r&&j-q[l]>a[i].f)l++;while(l<=r&&dp[i-1][q[r]]-a[i].c*q[r]+q[r]*q[r]*(a[i].x-a[i-1].x)>dp[i-1][j]-a[i].c*j+j*j*(a[i].x-a[i-1].x))r--;

q[++r]=j;

dp[i][j]=(l>r)?(1ll*inf*10000):dp[i-1][q[l]]+a[i].c*(j-q[l])+q[l]*q[l]*(a[i].x-a[i-1].x);

}

}

ans=1ll*inf*10000;for(int i=1;i<=n;i++)

ans=min(ans,dp[i][k]+k*k*(e-a[i].x));

printf("%lld\n",ans);return 0;

}

View Code

bzoj1698: [Usaco2007 Feb]Lilypad Pond 荷叶池塘

哇日常水题调很久系列。

最短路径怎么求很显然,往空地连1,荷叶连0。但是这样会发现在最短路松弛的时候记录的方案数会多算,因为可以走一圈荷叶代价为0再回来最短路径还是不变的,所以我们要想办法把边权0的去掉,就不会出现这种情况了。怎么办呢,提前dfs出两两空地能否不经过其他空地(可经过荷叶)到达就行了,然后连边边权为1,这样就去掉了所有边权为0的边,跑最短路。

#include#include#include#include

#define ll long long

using namespacestd;const int maxn=100,inf=1e9,dx[8]={-2,-1,1,2,2,1,-1,-2},dy[8]={1,2,2,1,-1,-2,-2,-1};struct poi{int tox,toy,pre;}e[500010];intn,m,cnt,front,rear,tot,sx,sy,tx,ty,tim;int map[maxn][maxn],b[maxn*maxn][3],h[2333333][3],dist[maxn][maxn],last[maxn][maxn],vvv[maxn][maxn];

ll ans[maxn][maxn];boolv[maxn][maxn],vv[maxn][maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x1,int y1,int x2,int y2){e[++tot].tox=x2;e[tot].toy=y2;e[tot].pre=last[x1][y1];last[x1][y1]=tot;}void spfa(int x,inty)

{for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)dist[i][j]=inf;

dist[x][y]=0;v[x][y]=1;front=0;rear=1;h[rear][1]=x;h[rear][2]=y;ans[x][y]=1;while(front!=rear)

{int nowx=h[++front][1],nowy=h[front][2];if(front==2333333)front=-1;++tim;//printf("%d %d %d %lld\n",nowx,nowy,dist[nowx][nowy],ans[nowx][nowy]);

for(int i=last[nowx][nowy],tox=e[i].tox,toy=e[i].toy;i;i=e[i].pre,tox=e[i].tox,toy=e[i].toy)

{if(vvv[tox][toy]==tim)continue;vvv[tox][toy]=tim;if(dist[tox][toy]==dist[nowx][nowy]+1)ans[tox][toy]+=ans[nowx][nowy];if(dist[tox][toy]>dist[nowx][nowy]+1)

{

dist[tox][toy]=dist[nowx][nowy]+1;

ans[tox][toy]=ans[nowx][nowy];if(!v[tox][toy])

{

v[tox][toy]=1;h[++rear][1]=tox;h[rear][2]=toy;if(rear==2333333)rear=-1;

}

}

}for(int i=0;i<8;i++)

{int tox=nowx+dx[i],toy=nowy+dy[i];if(tox<1||tox>n||toy<1||toy>m||map[tox][toy]==2||vvv[tox][toy]==tim||map[tox][toy]==1)continue;if(dist[tox][toy]==dist[nowx][nowy]+1)ans[tox][toy]+=ans[nowx][nowy];if(dist[tox][toy]>dist[nowx][nowy]+1)

{

dist[tox][toy]=dist[nowx][nowy]+1;

ans[tox][toy]=ans[nowx][nowy];if(!v[tox][toy])

{

v[tox][toy]=1;h[++rear][1]=tox;h[rear][2]=toy;if(rear==2333333)rear=-1;

}

}

}

}

}void dfs(int x,inty)

{

vv[x][y]=1;for(int i=0;i<8;i++)

{int xx=x+dx[i],yy=y+dy[i];if(xx<1||xx>n||yy<1||yy>m||map[xx][yy]==2)continue;if(map[xx][yy]==1&&vv[xx][yy]!=1)dfs(xx,yy);else if(map[xx][yy]!=1)b[++cnt][1]=xx,b[cnt][2]=yy;

}

}intmain()

{

read(n);read(m);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)

{

read(map[i][j]);if(map[i][j]==3)sx=i,sy=j;if(map[i][j]==4)tx=i,ty=j;if(map[i][j]==1)add(0,0,i,j);

}for(int i=last[0][0];i;i=e[i].pre)

{

cnt=0;if(!vv[e[i].tox][e[i].toy])dfs(e[i].tox,e[i].toy);for(int j=1;j<=cnt;j++)for(int k=1;k<=cnt;k++)

add(b[j][1],b[j][2],b[k][1],b[k][2]);

}

spfa(sx,sy);if(dist[tx][ty]==inf)printf("-1");else printf("%d\n%lld",dist[tx][ty]-1,ans[tx][ty]);

}

View Code

bzoj1777: [Usaco2010 Hol]rocks 石头木头

距离终点偶数长度的不用考虑.某个点的SG值为数量%(l+1),手推可以推出来。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{inttoo,pre;}e[maxn];intn,m,x,y,z,tot,l,t,ans;intv[maxn],dis[maxn],last[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}void dfs(intx)

{for(int i=last[x];i;i=e[i].pre)

dis[e[i].too]=dis[x]+1,dfs(e[i].too);

}intmain()

{

read(n);read(t);read(l);for(int i=2;i<=n;i++)read(x),read(v[i]),add(x,i);

dfs(1);for(int i=2;i<=n;i++)if(dis[i]&1)ans^=v[i]%(l+1);for(int i=1;i<=t;i++)

{

read(x);read(y);if(dis[x]&1)ans^=(v[x]%(l+1))^(y%(l+1));

v[x]=y;

printf("%s\n",ans?"Yes":"No");

}return 0;

}

View Code

bzoj1729: [Usaco2005 dec]Cow Patterns 牛的模式匹配

嗯昨天调了一天错误代码,最后还是放弃了抄题解吧T_T

可以预处理出某种数字出现次数的前缀,KMP的时候计算一下这个区间内比自己小的数的个数就是排名。然后再比较两个串这个区间内相同数字的出现次数是否相同,如果这个条件和排名都符合,那么这两位就是可以匹配的。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=100010,inf=1e9;intn,m,S,x1,x2,yy1,y2,cnt;int rk[3][maxn][30],s[3][maxn],f[maxn],ans[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}int getrk(int x,int i,intj)

{

x1=x2=yy1=y2=0;for(int k=1;k

yy1=rk[x][i][s[x][i]]-rk[x][i-j][s[x][i]];for(int k=1;k

y2=rk[2][j][s[2][j]];return (x1==x2)&&(yy1==y2);

}voidgetfail()

{

f[1]=1;f[2]=1;intj;for(int i=2;i<=m;i++)

{for(j=f[i];j>1&&(!getrk(2,i,j));j=f[j]);if(getrk(2,i,j))f[i+1]=j+1;else f[i+1]=1;

}

}voidkmp()

{int j=1;for(int i=1;i<=n;i++)

{while(j>1&&(!getrk(1,i,j)))j=f[j];if(getrk(1,i,j))j++;if(j==m+1)ans[++cnt]=i-m+1,j=f[j];

}

}intmain()

{

read(n);read(m);read(S);for(int i=1;i<=n;i++)read(s[1][i]);for(int i=1;i<=m;i++)read(s[2][i]);for(int i=1;i<=n;i++)

{for(int j=1;j<=S;j++)rk[1][i][j]=rk[1][i-1][j];

rk[1][i][s[1][i]]++;

}for(int i=1;i<=m;i++)

{for(int j=1;j<=S;j++)rk[2][i][j]=rk[2][i-1][j];

rk[2][i][s[2][i]]++;

}

getfail();kmp();

printf("%d\n",cnt);for(int i=1;i<=cnt;i++)printf("%d\n",ans[i]);return 0;

}

View Code

bzoj1605: [Usaco2008 Open]Crisis on the Farm 牧场危机

mdzz被输出方案最小字典序坑了好久TAT

预处理get[i][j]表示横坐标移动 i ,纵坐标移动 j 最后一步能救的牛。

f[i][j][k]表示已经走了i步,横坐标移动 j ,纵坐标移动 k最多能救几头牛,从四个方向转移+get[j][k]就行了。

方案就记录从哪转移来的,最小字典序我写了半天顺序实在调不下去了干脆写了个哈希来判...终于过了QAQ(蠢哭

#include#include#include#include#include#include#include#include

#define ull unsigned long long

using namespacestd;const int maxn=1010,inf=1e9,dx[4]={-1,0,0,1},dy[4]={0,-1,1,0};intn,m,K,x,y,z,tot,ans,posx,posy;int f[31][61][61],from[31][61][61][2],cowx[maxn],cowy[maxn],grax[maxn],gray[maxn],get[61][61];

ull hs[31][61][61],hss;char anss[31];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(m);read(K);for(int i=1;i<=n;i++)read(cowx[i]),read(cowy[i]);for(int i=1;i<=m;i++)

{

read(grax[i]),read(gray[i]);for(int j=1;j<=n;j++)if(abs(grax[i]-cowx[j])+abs(gray[i]-cowy[j])<=K)get[grax[i]-cowx[j]+30][gray[i]-cowy[j]+30]++;

}

memset(f,-32,sizeof(f));

f[0][30][30]=0;for(int i=1;i<=K;i++)

{for(int j=-i;j<=i;j++)

{for(int k=-i;k<=i;k++)if(abs(j)+abs(k)<=i)

{for(int l=0;l<4;l++)

{int x=j+dx[l],y=k+dy[l];if(f[i-1][x+30][y+30]+get[j+30][k+30]>f[i][j+30][k+30]||(f[i-1][x+30][y+30]+get[j+30][k+30]==f[i][j+30][k+30]&&hs[i-1][x+30][y+30]*5+l

{

f[i][j+30][k+30]=f[i-1][x+30][y+30]+get[j+30][k+30];from[i][j+30][k+30][0]=x;from[i][j+30][k+30][1]=y;

hs[i][j+30][k+30]=hs[i-1][x+30][y+30]*5+l;

}

}if(f[i][j+30][k+30]>ans||(f[i][j+30][k+30]==ans&&hs[i][j+30][k+30]

{

ans=f[i][j+30][k+30];

hss=hs[i][j+30][k+30];

posx=j;posy=k;

}

}

}

}

printf("%d\n",ans);for(int i=K;i;i--)

{int nx=from[i][posx+30][posy+30][0],ny=from[i][posx+30][posy+30][1];if(nx==posx)

{if(ny>posy)anss[i]='S';else anss[i]='N';

}else{if(nx>posx)anss[i]='W';else anss[i]='E';

}

posx=nx;posy=ny;

}for(int i=1;i<=K;i++)printf("%c",anss[i]);return 0;

}

View Code

bzoj3126: [Usaco2013 Open]Photo

噗哈哈看网上的题解全是DP+线段树或者单调队列优化,一眼差分约束,结果写差分约束真的艹过去了233(虽然跑的奇慢

对于一个区间[l,r],有条件sum[r]-sum[l-1]==1,可以看成sum[r]-sum[l-1]>=1,sum[r]-sum[l-1]<=1,于是l-1向r连边1,r向l-1连边-1。

还有约束条件sum[i]-sum[i-1]>=0,sum[i]-sum[i-1]<=1,于是i-1往i连边0,i往i-1连边1。

然后跑spfa最短路,有负环输出-1,就过了...等会去补个DP做法嘿嘿

#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=1000010,inf=1e9;structzs{ll dis,pre,too;}e[maxn];structpoi{ll pos,dis;};

priority_queueq;bool operator b.dis;};

ll to,i,now,n,m,s,t,x,y,z,tot,last[maxn],dis[maxn],mn,mx,ans;boolv[maxn],flag;void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y,int z){e[++tot].too=y;e[tot].dis=z;e[tot].pre=last[x];last[x]=tot;}void spfa(intx)

{

memset(dis,50,(n+1)<<3);dis[x]=0;q.push((poi){x,0});v[x]=1;while(!q.empty())

{for(to=e[i=last[now=q.top().pos]].too,q.pop();i;to=e[i=e[i].pre].too)if(dis[to]>dis[now]+e[i].dis)

{

ans++;if(ans>300000){printf("-1");flag=1;return;}

dis[to]=dis[now]+e[i].dis;if(!v[to])v[to]=1,q.push((poi){to,dis[to]});

}

v[now]=0;

}

}intmain()

{

read(n);read(m);

flag=0;for(int i=1;i<=m;i++)

{

read(x);read(y);

add(x-1,y,1);add(y,x-1,-1);;

}

mn=0;mx=n;for(int i=mn;i

spfa(mn);if(!flag)printf("%lld\n",dis[mx]);return 0;

}

View Code

写了线段树+DP反而慢了QAQ

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=200010,inf=1e9;intn,m,z,ans;int l[maxn],r[maxn],a[maxn<<2],x[maxn],y[maxn];

inlinevoid read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}

inlinevoid update(int x,int l,int r,int cx,intdelta)

{if(l==cx&&r==cx){a[x]=delta;return;}int mid=(l+r)>>1;if(cx<=mid)update(x<<1,l,mid,cx,delta);if(cx>mid)update(x<<1|1,mid+1,r,cx,delta);

a[x]=max(a[x<<1],a[x<<1|1]);

}

inlineint query(int x,int l,int r,int cl,intcr)

{if(cl<=l&&r<=cr)returna[x];int mid=(l+r)>>1,ret=-inf;if(cl<=mid)ret=max(ret,query(x<<1,l,mid,cl,cr));if(cr>mid)ret=max(ret,query(x<<1|1,mid+1,r,cl,cr));returnret;

}intmain()

{

read(n);read(m);for(int i=1;i<=n;i++)r[i]=i-1;for(int i=1;i<=m;i++)

{

read(x[i]);read(y[i]);

l[y[i]+1]=max(l[y[i]+1],x[i]);

r[y[i]]=min(r[y[i]],x[i]-1);

}for(int i=2;i<=n;i++)l[i]=max(l[i],l[i-1]);for(int i=n-1;i;i--)r[i]=min(r[i],r[i+1]);for(int i=1;i<=n;i++)

{int sum=l[i]<=r[i]?query(1,0,n,l[i],r[i])+1:-inf;ans=max(ans,sum);

update(1,0,n,i,sum);

}for(int i=1;i<=m;i++)if(query(1,0,n,x[i],y[i])<=0){puts("-1");return 0;}

printf("%d\n",ans);return 0;

}

View Code

bzoj3048: [Usaco2013 Jan]Cow Lineup

离散化后标尺法(两个指针l和r),保证区间数字种类<=k+1,用最大值更新答案。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,N,k,l,r,cnt,ans;inta[maxn],b[maxn],cntt[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(k);for(int i=1;i<=n;i++)read(a[i]),b[i]=a[i];N=n;

sort(b+1,b+1+N);N=unique(b+1,b+1+N)-b-1;for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+N,a[i])-b;

l=1;r=0;cnt=0;while(r

{

r++;if(!cntt[a[r]])cnt++;

cntt[a[r]]++;if(cnt>k+1)

{while(cntt[a[l]]!=1)cntt[a[l]]--,l++;

cntt[a[l]]=0;l++;

cnt--;

}if(cntt[a[r]]>ans)ans=cntt[a[r]];

}

printf("%d\n",ans);return 0;

}

View Code

bzoj2197: [Usaco2011 Mar]Tree Decoration

久违的金组水题...(MDZZ以后只要空间苟一律开long longQAQ

#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{inttoo,pre;}e[maxn];

ll n,fa,mn,tot;

ll ans;

ll c[maxn],nowc[maxn],t[maxn],last[maxn];void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}int dfs(intx)

{int mn=t[x];for(int i=last[x];i;i=e[i].pre)

mn=min(dfs(e[i].too),mn),nowc[x]-=c[e[i].too];if(nowc[x]>0)ans+=1ll*nowc[x]*mn;else c[x]-=nowc[x];returnmn;

}intmain()

{

read(n);for(int i=1;i<=n;i++)

{

read(fa);read(c[i]);read(t[i]);nowc[i]=c[i];if(i!=1)add(fa,i);

}

dfs(1);

printf("%lld\n",ans);

}

View Code

bzoj3407: [Usaco2009 Oct]Bessie's Weight Problem 贝茜的体重问题

水题一道就够了怎么来两道啊QAQ

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,v,x,y,z,tot;intf[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(v);read(n);for(int i=1;i<=n;i++)

{

read(x);for(int j=v;j>=x;j--)

f[j]=max(f[j],f[j-x]+x);

}

printf("%d\n",f[v]);return 0;

}

View Code

bzoj3887: [Usaco2015 Jan]Grass Cownoisseur

好题!帮我找出了以前好多的知识漏洞(卡了我好久TAT)

首先当然是要tarjan缩点。

预处理1到能到的点记作A集,能到1的点到1记作B集,并bfs求出1到A集,B集到1的最长路,枚举每一条边,如果端点分别是A集和B集,那么就把这条边,反向,两条最长路加起来更新答案。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=100010,inf=1e9;struct poi{int x,too,pre;}e[maxn*2],e2[maxn*2],e3[maxn*2];intn,m,x,y,z,tot,tott,tot2,tot3,top,color,ans;intlen1[maxn],len2[maxn],dfn[maxn],low[maxn],st[maxn],lack[maxn],col[maxn],num[maxn],last[maxn],last2[maxn],last3[maxn],v[maxn],h[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,int y){e[++tot].x=x;e[tot].too=y;e[tot].pre=last[x];last[x]=tot;}void add2(int x,int y){e2[++tot2].x=x;e2[tot2].too=y;e2[tot2].pre=last2[x];last2[x]=tot2;}void add3(int x,int y){e3[++tot3].x=x;e3[tot3].too=y;e3[tot3].pre=last3[x];last3[x]=tot3;}void tarjan(intx)

{

dfn[x]=low[x]=++tott;st[++top]=x;lack[x]=top;for(int i=last[x],too=e[i].too;i;i=e[i].pre,too=e[i].too)if(!dfn[too])tarjan(too),low[x]=min(low[x],low[too]);else if(!col[too])low[x]=min(low[x],dfn[too]);if(dfn[x]==low[x])for(color++;top>=lack[x];top--)col[st[top]]=color,num[color]++;

}void dfs1(intx)

{

v[x]=1;for(int i=last2[x],too=e2[i].too;i;i=e2[i].pre,too=e2[i].too)dfs1(too);

}void dfs2(intx)

{

v[x]=2;for(int i=last3[x],too=e3[i].too;i;i=e3[i].pre,too=e3[i].too)dfs2(too);

}voidbfs1()

{

top=0;int front=0,rear=1;h[1]=col[1];len1[col[1]]=num[col[1]];while(front!=rear)

{int now=h[++front];if(front==maxn)front=-1;for(int i=last2[now];i;i=e2[i].pre)

{

h[++rear]=e2[i].too;if(rear==maxn)rear=-1;

len1[e2[i].too]=max(len1[e2[i].too],len1[now]+num[e2[i].too]);

}

}

}voidbfs2()

{

top=0;int front=0,rear=1;h[1]=col[1];len2[col[1]]=num[col[1]];while(front!=rear)

{int now=h[++front];if(front==maxn)front=-1;for(int i=last3[now];i;i=e3[i].pre)

{

h[++rear]=e3[i].too;if(rear==maxn)rear=-1;

len2[e3[i].too]=max(len2[e3[i].too],len2[now]+num[e3[i].too]);

}

}

}intmain()

{

read(n);read(m);for(int i=1;i<=m;i++)read(x),read(y),add(x,y);for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);for(int i=1;i<=tot;i++)if(col[e[i].x]!=col[e[i].too])add2(col[e[i].x],col[e[i].too]),add3(col[e[i].too],col[e[i].x]);

dfs1(col[1]);dfs2(col[1]);

bfs1();bfs2();

ans=2*num[col[1]];for(int i=1;i<=tot2;i++)

{if((v[e2[i].x]==2||e2[i].x==col[1])&&(v[e2[i].too]==1||e2[i].too==col[1]))

ans=max(ans,len2[e2[i].x]+len1[e2[i].too]);

}

printf("%d\n",ans-num[col[1]]);return 0;

}

View Code

bzoj1727: [Usaco2006 Open]The Milk Queue 挤奶队列

不会...知道是贪心但是不会贪...题解好喵喵啊

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{intx,y;}a[maxn];intn,m,x,y,z,tot;

ll ans,sum,rest;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool cmp(poi a,poi b){return min(a.x,b.y)

{

read(n);for(int i=1;i<=n;i++)read(a[i].x),read(a[i].y),sum+=a[i].y;

sort(a+1,a+1+n,cmp);for(int i=1;i<=n;i++)

{if(a[i].x<=rest)rest-=a[i].x;else ans+=a[i].x-rest,rest=0;

rest+=a[i].y;

}

printf("%lld\n",ans+sum);return 0;

}

View Code

bzoj3312: [Usaco2013 Nov]No Change

看见K<=16就知道要状压DP了...

f[i]表示硬币状态为i最多能买多少东西。

f[i]=max(f[i^(1<

又忘记输出-1 WA了一次QAQ

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,k,x,y,z,tot,ans,state;intcoin[maxn],sum[maxn],f[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(k);read(n);for(int i=1;i<=k;i++)read(coin[i]);for(int i=1;i<=n;i++)read(sum[i]),sum[i]+=sum[i-1];

state=(1<

f[0]=0;for(int i=1;i<=state;i++)

{for(int j=1;j<=k;j++)if((i&(1<

{int l=f[i^(1<

{int mid=(l+r+1)>>1;if(sum[mid]-summ<=coin[j])l=mid;else r=mid-1;

}

f[i]=max(f[i],l);

}

}

ans=-inf;for(int i=0;i<=state;i++)

{if(f[i]!=n)continue;int rest=0;for(int j=1;j<=k;j++)if(!(i&(1<

ans=max(ans,rest);

}

printf("%d\n",ans!=-inf?ans:-1);return 0;

}

View Code

bzoj2272: [Usaco2011 Feb]Cowlphabet 奶牛文字

一眼题...因为一个sb错误错了好久(虽然要是没这个错我不会发现自己模数写错两次T_T(1e9+7->987654321->97654321

f[i][j][k]表示有i个大写字母,j个小写字母,最后一位是k的方案数。注意这个不能和背包一样写。。因为有了那最后一维...

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9,mod=97654321;intn,u,l,tot,ans;int f[256][256][256];char s[256][3];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool is1(char ch){return (ch<='Z'&&ch>='A');}bool is2(char ch){return (ch<='z'&&ch>='a');}int up(int x){return is1(s[x][1])+is1(s[x][2]);}int low(int x){return is2(s[x][1])+is2(s[x][2]);}intmain()

{

read(u);read(l);read(n);for(int i=1;i<=n;i++)scanf("%s",s[i]+1);for(int i=1;i<=n;i++)f[up(i)][low(i)][s[i][2]]++;for(int j=0;j<=u;j++)for(int k=0;k<=l;k++)if(j+k>2)for(int i=1;i<=n;i++)

{if(j

f[j][k][s[i][2]]+=f[j-is1(s[i][2])][k-is2(s[i][2])][s[i][1]];

f[j][k][s[i][2]]>=mod&&(f[j][k][s[i][2]]-=mod);

}for(int j=0;j<=25;j++)

ans+=f[u][l]['a'+j],ans>=mod&&(ans-=mod),ans+=f[u][l]['A'+j],ans>=mod&&(ans-=mod);

printf("%d\n",ans);return 0;

}

View Code

bzoj1750: [Usaco2005 qua]Apple Catching

一眼题*2....f[i][j][0/1]表示第i分钟,走了j次,在第1/2棵树下的最大收益

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,w,x,y,z,tot,ans;int f[1010][50][2],a[1010];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(w);for(int i=1;i<=n;i++)read(a[i]);for(int i=1;i<=n;i++)

{

f[i][0][0]=f[i-1][0][0]+(a[i]==1);

f[i][0][1]=f[i-1][0][1]+(a[i]==2);

ans=max(ans,max(f[i][0][0],f[i][0][1]));for(int j=1;j<=min(i,w);j++)

{

f[i][j][0]=max(f[i-1][j][0],f[i-1][j-1][1])+(a[i]==1);

f[i][j][1]=max(f[i-1][j][1],f[i-1][j-1][0])+(a[i]==2);

ans=max(ans,max(f[i][j][0],f[i][j][1]));

}

}

printf("%d\n",ans);return 0;

}

View Code

bzoj1736: [Usaco2005 jan]The Wedding Juicer 婚宴的榨汁机

从四周向中间宽搜,每次出队高度最小的点,并记录来的路上的最大值,拿这个最大值减去当前高度,求和就是答案了。

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=310,inf=1e9,dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};struct poi{intx,y,h;};

priority_queueq;bool operatorb.h;}intn,m,x,y,z,tot;inth[maxn][maxn];boolv[maxn][maxn];

ll ans;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}voidbfs()

{while(!q.empty())

{

poi now=q.top();q.pop();for(int i=0;i<4;i++)

{int xx=now.x+dx[i],yy=now.y+dy[i];if(xx<1||xx>n||yy<1||yy>m||v[xx][yy])continue;if(h[xx][yy]

{

ans+=now.h-h[xx][yy];

h[xx][yy]=now.h;

}

v[xx][yy]=1;q.push((poi){xx,yy,h[xx][yy]});

}

}

}intmain()

{

read(m);read(n);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)

read(h[i][j]);for(int i=1;i<=m;i++)

q.push((poi){1,i,h[1][i]}),q.push((poi){n,i,h[n][i]}),v[1][i]=1,v[n][i]=1;for(int i=2;i

q.push((poi){i,1,h[i][1]}),q.push((poi){i,m,h[i][m]}),v[i][1]=1,v[i][m]=1;

bfs();printf("%lld\n",ans);return 0;

}

View Code

bzoj1779: [Usaco2010 Hol]Cowwar 奶牛战争

刷了几题银组刷不下去了。。还是回来刷金组吧TAT

看这数据范围完全想不到网络流啊,后来才知道如果容量全部为1的话dinic的效率实际上是O(min(n^(2/3),m^(1/2))*m)...所以能跑过

四分图。

源点连所有J,J连所有走一步能到的不是T的点和自己所在的点,这些点拆成i和i',连边,i'和所有相邻的T连边,T和汇点连边,容量都是1,跑最大流。

#include#include#include#include#include#include

using namespacestd;const int inf=1e9,maxn=60010;struct poi{int too,pre,cf;}e[500010],e2[500010];intn,m,tot,tot2,ans,x,y,z,front,rear,sum;inth[maxn],v[maxn],last[maxn],last2[maxn],dis[maxn],cur[maxn];chars[maxn];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void add(int x,inty)

{

e[++tot].too=y;e[tot].cf=1;e[tot].pre=last[x];last[x]=tot;

e[++tot].too=x;e[tot].pre=last[y];last[y]=tot;

}void add2(int x,int y){e2[++tot2].too=y;e2[tot2].pre=last2[x];last2[x]=tot2;}boolbfs()

{for(int i=0;i<=sum;i++)v[i]=0,dis[i]=-1;

dis[0]=0;v[0]=1;h[1]=0;front=0;rear=1;while(front!=rear)

{int now=h[++front];if(front==maxn)front=-1;for(int i=last[now];i;i=e[i].pre)

{int too=e[i].too;if((!v[too])&&e[i].cf)

{

dis[too]=dis[now]+1;if(too==sum)return 1;

v[too]=1;h[++rear]=too;if(rear==maxn)rear=-1;

}

}

}return 0;

}int dfs(int x,intf)

{int flow=0,tmp;if(x==sum)returnf;for(int &i=cur[x];i;i=e[i].pre)

{int too=e[i].too;if(dis[too]==dis[x]+1&&e[i].cf)

{

tmp=dfs(too,min(f-flow,e[i].cf));

e[i].cf-=tmp;e[i^1].cf+=tmp;flow+=tmp;if(f==flow)returnf;

}

}returnflow;

}voiddinic()

{while(bfs())

{for(int i=0;i<=sum;i++)cur[i]=last[i];

ans+=dfs(0,inf);

}

}intmain()

{

tot=1;

read(n);read(m);sum=(n<<2)+1;

scanf("%s",s+1);for(int i=1;i<=m;i++)read(x),read(y),add2(x,y),add2(y,x);for(int i=1;i<=n;i++)

{if(s[i]=='J')

{

add(0,i);add(i,i+n);add(i+n,i+(n<<1));for(int j=last2[i],too=e2[j].too;j;j=e2[j].pre,too=e2[j].too)if(s[too]!='T')add(i,too+n);

}else if(s[i]!='T')add(i+n,i+(n<<1));if(s[i]=='T')

{

add(i+n*3,sum);for(int j=last2[i],too=e2[j].too;j;j=e2[j].pre,too=e2[j].too)

add(too+(n<<1),i+n*3);

}

}

dinic();

printf("%d\n",ans);return 0;

}

View Code

bzoj4094: [Usaco2013 Dec]Optimal Milking

一眼题。。。线段树维护选左边右边,左边,右边,不选的最大值。

一开始没开long long WA了一发,改完交就AC了,好爽(假·1A

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;struct poi{ll lr,l,r,none;}a[maxn*4];

ll n,m,x,y,z,tot;

ll ans;void read(ll &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}void pushup(int x,int l,intr)

{if(l==r)return;

a[x].lr=max(a[x<<1].l+a[x<<1|1].r,max(a[x<<1].lr+a[x<<1|1].r,a[x<<1].l+a[x<<1|1].lr));

a[x].l=max(a[x<<1].l+a[x<<1|1].l,max(a[x<<1].l+a[x<<1|1].none,a[x<<1].lr+a[x<<1|1].none));

a[x].r=max(a[x<<1].r+a[x<<1|1].r,max(a[x<<1].none+a[x<<1|1].r,a[x<<1].none+a[x<<1|1].lr));

a[x].none=max(a[x<<1].r+a[x<<1|1].none,max(a[x<<1].none+a[x<<1|1].l,a[x<<1].none+a[x<<1|1].none));

}void build(int x,int l,intr)

{if(l==r){read(a[x].lr);return;}int mid=(l+r)>>1;

build(x<<1,l,mid);build(x<<1|1,mid+1,r);

pushup(x,l,r);

}void update(int x,int l,int r,int cx,intdelta)

{if(l==cx&&r==cx){a[x].lr=delta;return;}int mid=(l+r)>>1;if(cx<=mid)update(x<<1,l,mid,cx,delta);if(cx>mid)update(x<<1|1,mid+1,r,cx,delta);

pushup(x,l,r);

}intmain()

{

read(n);read(m);build(1,1,n);for(int i=1;i<=m;i++)

{

read(x);read(y);

update(1,1,n,x,y);

ans+=max(a[1].lr,max(a[1].none,max(a[1].l,a[1].r)));

}

printf("%lld\n",ans);return 0;

}

View Code

bzoj3886: [Usaco2015 Jan]Moovie Mooving

很早就写了一直懒得写题解....

状压DP f[i]表示电影的状态为i最多能看多长时间,随便转移

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=30,inf=1e9;intn,m,x,y,z,tot,ans,l,r,mid,L,cnt;int f[2000010],len[maxn],num[maxn],a[maxn][maxn*100];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}bool check(int i,int x){return a[i][mid]<=x+1;}intmain()

{

read(n);read(L);for(int i=1;i<=n;i++)

{

read(len[i]);read(num[i]);for(int j=1;j<=num[i];j++)

read(a[i][j]);

}

memset(f,-32,sizeof(f));f[0]=0;ans=inf;for(int i=0;i

{

cnt=0;for(int j=1;j<=n;j++)if(!(i&(1<

{

cnt++;

l=0;r=num[j];while(l

{

mid=(l+r+1)>>1;if(check(j,f[i]))l=mid;else r=mid-1;

}if(!l)continue;

f[i|(1<

}if(f[i]>=L)ans=min(ans,n-cnt);

}

printf("%d\n",ans!=inf?ans:-1);return 0;

}

View Code

bzoj1915: [Usaco2010 Open]奶牛的跳格子游戏

DP+单调队列优化

f[i]表示去的时候跳到i,回来的时候跳到i-1的最大收益。预处理sum表示所有正数的前缀和(因为一个可以自由跳的区间内负数一定不取

f[i] =max(f[j] + a[i] + a[i-1] + sum[i-2] - sum[j]) {1<=j

每次把f[i-1]-sum[i-1]加入单调队列就行了。

交了5发因为空间开太大没艹上#1....丢人

#2也是不错的嘿嘿

bzoj4393: [Usaco2015 Dec]Fruit Feast

果然新题如果AC人数少就肯定是水题了...

显然只有四种情况,不喝水,吃A喝水,吃B喝水,吃AB喝水,记得判一下饱涨值够不够吃

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,n1,n2,n3,A,B,a,b,ans;void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);read(A);read(B);

a=A>>1;b=B>>1;

n1=n-a;n2=n-b;n3=n-a-b;for(int i=0;i<=n/A;i++)

ans=max(ans,i*A+B*((n-i*A)/B));if(n>=A)for(int i=0;i<=n1/A;i++)

ans=max(ans,i*A+B*((n1-i*A)/B)+a);if(n>=B)for(int i=0;i<=n2/A;i++)

ans=max(ans,i*A+B*((n2-i*A)/B)+b);if(n>=A+B)for(int i=0;i<=n3/A;i++)

ans=max(ans,i*A+B*((n3-i*A)/B)+a+b);

printf("%d\n",ans);return 0;

}

View Code

bzoj4580: [Usaco2016 Open]248

久违的1A........

嗯这题又印证了上题题解的第一句话

区间DP,f[l][r]=max(f[l][r],f[l][k]+1) (f[l][k]==f[k+1][r])

#include#include#include#include#include#include#include#include

#define ll long long

using namespacestd;const int maxn=500010,inf=1e9;intn,m,x,y,z,tot,ans;int f[250][250];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}intmain()

{

read(n);

memset(f,-1,sizeof(f));for(int i=1;i<=n;i++)read(f[i][i]);for(int i=1;i<=n;i++)for(int j=1;i+j-1<=n;j++)

{int L=j,R=i+j-1;for(int k=L;k

f[L][R]=max(f[L][R],f[L][k]+1);

ans=max(ans,f[L][R]);

}

printf("%d\n",ans);return 0;

}

View Code

bzoj3939: [Usaco2015 Feb]Cow Hopscotch

f[i][j]=sigma(f[k][l]) {k

我们让每一次转移都求出相同颜色的方案数,再用总方案数减去就行了。注意是每一次转移都要被总方案数减,否则相当于这条路径上全部都相同,这样的补集是至少有一个不同而不是全都不同。

显然这个DP方程就是统计一个前缀的和,对每个颜色建一棵线段树动态开点+扫描线就好了。

#include#include#include#include

using namespacestd;const int maxn=760,inf=1e9,mo=1e9+7;struct poi{int sum;}a[maxn*maxn*10];intn,m,K,cnt,cl,cr,cx;int col[maxn][maxn],tot[maxn][maxn],sum[maxn][maxn],rt[maxn*maxn*10],lt[maxn*maxn*10],f[maxn][maxn],root[maxn*maxn*10];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}

inlineint mod(int x){return x>=mo?x-mo:x;}void update(int &x,int l,int r,intdelta)

{if(!x)x=++cnt;a[x].sum=mod(a[x].sum+delta);if(l==r)return;int mid=(l+r)>>1;if(cx<=mid)update(lt[x],l,mid,delta);else update(rt[x],mid+1,r,delta);

}int query(int x,int l,intr)

{if(!x)return 0;if(cl<=l&&r<=cr)returna[x].sum;int mid=(l+r)>>1,ret=0;if(cl<=mid)ret+=query(lt[x],l,mid);if(cr>mid)ret+=query(rt[x],mid+1,r);

ret=mod(ret);returnret;

}intmain()

{

read(n);read(m);read(K);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)

read(col[i][j]);

sum[1][1]=f[1][1]=1;for(int i=2;i<=n;i++)

{for(int j=1;j<=m;j++)

{if(i==1&&j==1)continue;

cl=1,cr=j-1;

f[i][j]=mod(sum[i-1][j-1]+mo-query(root[col[i][j]],1,m));

sum[i][j]=(1ll*sum[i][j-1]+1ll*sum[i-1][j]-1ll*sum[i-1][j-1]+1ll*f[i][j]+mo)%mo;

}for(int j=1;j<=m;j++)

cx=j,update(root[col[i][j]],1,m,f[i][j]);

}

printf("%d\n",f[n][m]);

}

View Code

bzoj1737: [Usaco2005 jan]Naptime 午睡时间

不考虑环的话则有 f[i][j][1]=max(f[i-1][k][1]+a[j],f[i-1][k][0]){k

f[i][j][0]=max(f[i-1][k][1],f[i-1][k][0])

初始状态f[1][1][1]=f[1][0][0]=0;

对于环多考虑一种跨环的情况,也就是1必须睡觉,强制跨环的话初始状态为f[1][1][1]=0 最后答案为f[n][m][1]+a[1]

#include#include#include#include#include#include

using namespacestd;const int maxn=4010,inf=1e9;intn,m,ans;int a[maxn],f[2][maxn][2];void read(int &k)

{int f=1;k=0;char c=getchar();while(c'9')c=='-'&&(f=-1),c=getchar();while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();

k*=f;

}int max(int a,int b){return a>b?a:b;}intmain()

{

read(n);read(m);for(int i=1;i<=n;i++)read(a[i]);

memset(f,200,sizeof(f));

f[1][1][1]=f[1][0][0]=0;for(int i=2;i<=n;i++)

{for(int j=0;j<=m;j++)

{if(j)f[i&1][j][1]=max(f[(i&1)^1][j-1][0],f[(i&1)^1][j-1][1]+a[i]);

f[i&1][j][0]=max(f[(i&1)^1][j][1],f[(i&1)^1][j][0]);

}

ans=max(ans,max(f[i&1][m][1],f[i&1][m][0]));

}

memset(f,200,sizeof(f));

f[1][1][1]=0;for(int i=2;i<=n;i++)

{for(int j=0;j<=m;j++)

{if(j)f[i&1][j][1]=max(f[(i&1)^1][j-1][0],f[(i&1)^1][j-1][1]+a[i]);

f[i&1][j][0]=max(f[(i&1)^1][j][1],f[(i&1)^1][j][0]);

}

}

ans=max(ans,f[n&1][m][1]+a[1]);

printf("%d\n",ans);

}

View Code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Complete the Mint and Coin classes so that the coins created by a mint have the correct year and worth. - Each Mint instance has a year stamp. The update method sets the year stamp to the current_year class attribute of the Mint class. - The create method takes a subclass of Coin and returns an instance of that class stamped with the mint's year (which may be different from Mint.current_year if it has not been updated.) - A Coin's worth method returns the cents value of the coin plus one extra cent for each year of age beyond 50. A coin's age can be determined by subtracting the coin's year from the current_year class attribute of the Mint class. ```python class Mint: """A mint creates coins by stamping on years. The update method sets the mint's stamp to Mint.current_year. >>> mint = Mint() >>> mint.year 2020 >>> dime = mint.create(Dime) >>> dime.year 2020 >>> Mint.current_year = 2100 # Time passes >>> nickel = mint.create(Nickel) >>> nickel.year # The mint has not updated its stamp yet 2020 >>> nickel.worth() # 5 cents + (80 - 50 years) 35 >>> mint.update() # The mint's year is updated to 2100 >>> Mint.current_year = 2175 # More time passes >>> mint.create(Dime).worth() # 10 cents + (75 - 50 years) 35 >>> Mint().create(Dime).worth() # A new mint has the current year 10 >>> dime.worth() # 10 cents + (155 - 50 years) 115 >>> Dime.cents = 20 # Upgrade all dimes! >>> dime.worth() # 20 cents + (155 - 50 years) 125 """ current_year = 2020 def init(self): self.update() def create(self, kind): "*** YOUR CODE HERE " def update(self): " YOUR CODE HERE " class Coin: def init(self, year): self.year = year def worth(self): " YOUR CODE HERE ***" class Nickel(Coin): cents = 5 class Dime(Coin): cents = 10
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值