bzoj usaco 金组水题题解(2)

续。。。。。TAT这回不到50题编辑器就崩了。。

这里塞40道吧= =

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

  比较经典的最小割?。。然而一开始还是不会QAQ

  和地震伤害1的区别在于这题求的是最少的损坏牧场数目。把牧场拆点,因为要让1和被报告的点不联通,把1归到S集,被报告的点归到T集,就变成求最小割了。

  具体建图:

    假设点拆成x和x’,x和x‘间连边(就是等下要割的)。被报告的点和1点:容量无穷大(不能割);其他点容量为1。

    原图中相连的边就按照二分图正常姿势,出点连到入点,容量无穷大(路没坏)。

    最后就是s连1,被报告的点连t,容量都无穷大

  dinic大法好。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=3003;
 6 const int inf=1023333333;
 7 struct zs{
 8     int too,pre,flow;
 9 }e[98233];
10 int last[maxn<<1],dl[maxn<<1],l,r,now,tot=1;
11 short dis[maxn<<1];
12 bool u[maxn];
13 int i,j,k,n,m,a,b,s,t,p,ans;
14  
15 int ra;char rx;
16 inline int read(){
17     rx=getchar();ra=0;
18     while(rx<'0'||rx>'9')rx=getchar();
19     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
20 }
21 inline void insert(int a,int b,int c){
22 //  printf("   %d-->%d  %d\n",a,b,c==1?1:233);
23     e[++tot].too=b;e[tot].flow=c;e[tot].pre=last[a];last[a]=tot;
24     e[++tot].too=a;e[tot].flow=0;e[tot].pre=last[b];last[b]=tot;
25 }
26 inline bool bfs(){
27     memset(dis,255,(t+1)<<1);
28     l=0;r=1;dl[1]=s;dis[s]=0;
29     while(l<r&&dis[t]==-1)for(now=dl[++l],i=last[now];i;i=e[i].pre)if(e[i].flow&&dis[e[i].too]==-1)
30         dis[e[i].too]=dis[now]+1,dl[++r]=e[i].too;
31 //  for(i=1;i<=t;i++)printf("  %d %d\n",i,dis[i]);
32     return dis[t]!=-1;
33 }
34 int dfs(int x,int mx){
35     if(x==t||!mx)return mx;
36     int used=0,i,w;
37     for(i=last[x];i;i=e[i].pre)if(dis[e[i].too]==dis[x]+1&&e[i].flow){
38         w=dfs(e[i].too,min(mx-used,e[i].flow));if(w){
39             e[i].flow-=w;e[i^1].flow+=w;
40             used+=w;if(used==mx)return mx;
41         }
42     }
43     dis[x]=-1;return used;
44 }
45 int main(){
46     n=read();m=read();p=read();s=0;t=n+n+1;
47     for(i=1;i<=m;i++)a=read(),b=read(),insert(a+n,b,inf),insert(b+n,a,inf);
48     for(i=1;i<=p;i++)a=read(),u[a]=1,insert(a,a+n,inf),insert(a+n,t,inf);
49     for(i=2;i<=n;i++)if(!u[i])insert(i,i+n,1);if(!u[1])insert(1,1+n,inf);
50     insert(s,1,inf);
51     while(bfs())ans+=dfs(s,inf);
52     printf("%d\n",ans);
53     return 0;
54 }
55 
56 View
View Code

 

bzoj 2200: [Usaco2011 Jan]道路和航线

正解:根据题目,一条航线就是图的一条割边。。  所以先把图中各个联通块单独拿出来,在联通块里跑最短路(这时联通块里没有负权边,就用Dijkstra+堆去求)。再按联通块之间的拓扑顺序把整张图的最短路求出来。

  又wa又T一时爽。。一开始是没注意负权边直接上dij,然后是spfa被卡。。。。spfa+slf就可过了= =巧妙的避开了正解(逃。。。

  话说spfa好像并不难卡?。。。以后得小心了QAQ

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 const int maxn=25233;
 8 const int mx=25233;
 9 struct zs{
10     int too,pre,dis;
11 }e[152333];
12 int dl[mx+1];
13 int i,j,k,n,m,m1,s,tot,a,b,c;
14 int dis[maxn],last[maxn];
15 bool u[maxn];
16 int ra,fh;char rx;
17 inline int getnext(int x){
18     x++;if(x>=mx)return 1;
19     return x;
20 }
21 inline int getpre(int x){
22     x--;if(x<1)return mx-1;
23     return x;
24 }
25 inline int read(){
26     rx=getchar();ra=0;fh=1;
27     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
28     if(rx=='-')fh=-1,rx=getchar();
29     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
30 }
31 inline void insert(int a,int b,int c){
32     e[++tot].too=b;e[tot].dis=c;e[tot].pre=last[a];last[a]=tot;
33 }
34  
35 inline void spfa(){
36     int size=1,i,now,to,l,r;//,tt=0;
37     memset(dis,60,(n+1)<<2);
38     dis[s]=0;dl[1]=s;l=0;r=1;
39     while(size){
40         l=getnext(l);size--;
41         now=dl[l];u[now]=0;
42         for(i=last[now],to=e[i].too;i;i=e[i].pre,to=e[i].too)if(dis[to]>dis[now]+e[i].dis){
43             dis[to]=dis[now]+e[i].dis;
44             if(!u[to])
45                 if(size&&dis[to]<dis[dl[getnext(l)]])dl[l]=to,l=getpre(l),size++,u[to]=1;
46                 else r=getnext(r),dl[r]=to,size++,u[to]=1;
47         }
48     }
49 }
50 int main(){
51     n=read();m=read();m1=read();s=read();
52     for(i=1;i<=m;i++)a=read(),b=read(),c=read(),insert(a,b,c),insert(b,a,c);
53     for(i=1;i<=m1;i++)a=read(),b=read(),c=read(),insert(a,b,c);
54     spfa();
55     for(i=1;i<=n;i++)if(dis[i]<923333333)printf("%d\n",dis[i]);else puts("NO PATH");
56     return 0;
57 }
View Code

 

bzoj 1575: [Usaco2009 Jan]气象牛Baric

  正常dp。。。先预处理出sum[i][j]表示s集中选了第i天和第j天时,原序列中第i+1~j-1天的误差值之和。pre[i]表示s集中第一个选了i的话,1~i-1天的误差和。aft[i]表示s集中最后一个是第i天的话i+1~n天的误差和。

   f[i][j]表示最后选第i天,总共选了j天的第1~i天的最小误差。初始化f[i][1]=pre[i];

  f[i][j]=min{f[k][j-1]+sum[k][i]},(1<=k<i,2<=j<=n)。如果min{ f[i][j]+aft[i] }<=E的话就可以了

  总复杂度O(n^3)。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstdlib>
 4 using namespace std;
 5 const int maxn=102;
 6 int i,j,k,n,m,l,r,mid,ans,tmp;
 7 int a[maxn],sum[maxn][maxn],aftsum[maxn],befsum[maxn];
 8 int f[maxn][maxn];
 9 int ra;char rx;
10 inline int read(){
11     rx=getchar();ra=0;
12     while(rx<'0'||rx>'9')rx=getchar();
13     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
14 }
15 int main(){
16     n=read();m=read();
17     for(i=1;i<=n;i++)a[i]=read();
18     for(i=1;i<n;i++)for(j=i+1;j<=n;j++)
19         for(k=i+1;k<j;k++)sum[i][j]+=abs((a[k]<<1)-a[i]-a[j]);
20     for(i=n;i;i--){
21         for(j=n;j>i;j--)aftsum[i]+=abs(a[j]-a[i])<<1;
22         for(j=1;j<i;j++)befsum[i]+=abs(a[j]-a[i])<<1;
23     }
24     for(i=1;i<=n;i++)f[i][1]=befsum[i];
25     ans=102333333;
26     for(j=1;j<=n&&ans>m;j++){
27         for(i=j;i<=n;i++){
28             if(j>1)
29             for(f[i][j]=f[1][j-1]+sum[1][i],k=2;k<i;k++)if(f[k][j-1]+sum[k][i]<f[i][j])f[i][j]=f[k][j-1]+sum[k][i];
30             if(f[i][j]+aftsum[i]<ans)ans=f[i][j]+aftsum[i];
31         }
32     }
33     printf("%d %d\n",j-1,ans);
34     return 0;
35 }
View Code

 

bzoj 1755: [Usaco2005 qua]Bank Interest

  如题。。就是求算存钱若干年后的本息之和

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define d double
 5 using namespace std;
 6 int i,j,k,n,m,r,y;
 7 d ans;
 8 int main(){
 9     scanf("%d%d%d",&r,&m,&y);
10     ans=(d)(100+r)/(d)100.0;
11     for(i=2;i<=y;i++)ans=ans*(d)(100+r)/(d)100.0;
12     printf("%d\n",y?(int)(ans*m):m);
13     return 0;
14 }
View Code

 

bzoj 1774: [Usaco2009 Dec]Toll 过路费

  floyd。。http://www.cnblogs.com/czllgzmzl/p/5070943.html

 

bzoj 1775: [Usaco2009 Dec]Vidgame 电视游戏问题

  一开始以为是状压。。。结果发现数据范围是给01背包的= =

  ans[i]表示指出i元的最多产出,f[i]表示当前游戏平台内,花i元买游戏的最大产出。初始化f[i]=ans[i-P](买游戏得先买平台),(P是当前游戏平台的价格)f[i]就是个01背包。

  ans[i]=max(ans[i],f[i])。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 int cost,val;
 6 int need,num;
 7 int f[100233],g[100233];
 8 int i,j,k,n,m,maxv,tmp,ans;
 9 int ra;char rx;
10 inline int read(){
11     rx=getchar();ra=0;
12     while(rx<'0'||rx>'9')rx=getchar();
13     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
14 }
15 int main(){
16     n=read();maxv=read();
17     for(i=1;i<=n;i++){
18         need=read();num=read();
19         memset(g,150,need<<2);
20         for(j=need;j<=maxv;j++)g[j]=f[j-need];
21         for(j=0;j<num;j++)
22             for(cost=read(),val=read(),k=maxv,tmp=k-cost;tmp>=0;k--,tmp--)
23                 if(g[tmp]+val>g[k])g[k]=g[tmp]+val;
24         for(j=maxv;j>=need;j--)if(f[j]<g[j])f[j]=g[j];
25     }
26     for(i=maxv;i>=0;i--)if(f[i]>ans)ans=f[i];
27     printf("%d\n",ans);
28     return 0;
29 }
View Code

 

bzoj 1696:  [Usaco2007 Feb]Building A New Barn新牛舍

  中位数。。好吧是平面上的。设奶牛吃草位置为x[],y[],理想情况下(ansx,ansy)分别是x数组、y数组排序后的中位数。

  n为奇数时,最理想的点是唯一的。但如果那个地方已经有奶牛吃草了的话,就尝试下它相邻4个点(这是仅有的可能次优的几个)。

  n为偶数时,点(x[n/2],y[n/2])与点(x[n/2+1],y[n/2+1])组成的矩形内的点都是最优的。(x、y已排序)最优点的个数要减去在矩形里吃草的牛的数量。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 using namespace std;
 7 const int maxn=10233;
 8 struct zs{
 9     int x,y;
10 }a[maxn];
11 int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0};
12 int i,j,k,n,m,maxv,tmp,ans,x,y,nowx,nowy,x1,y1,sum;
13 bool cant;
14 int ra,fh;char rx;
15 inline int read(){
16     rx=getchar();ra=0;fh=1;
17     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
18     if(rx=='-')rx=getchar(),fh=-1;
19     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
20 }
21 bool cmp1(zs a,zs b){
22     return a.x<b.x;
23 }
24 bool cmp2(zs a,zs b){
25     return a.y<b.y;
26 }
27 inline int get(int x,int y){
28     int ans=0,i;
29     for(i=1;i<=n;i++)ans+=abs(x-a[i].x)+abs(y-a[i].y);return ans;
30 }
31 int main(){
32     n=read();
33     for(i=1;i<=n;i++)a[i].x=read(),a[i].y=read();
34     ans=2023333333;
35     if(n&1){
36         sort(a+1,a+1+n,cmp1);x=a[(n+1)>>1].x;
37         sort(a+1,a+1+n,cmp2);y=a[(n+1)>>1].y;
38         for(i=1;i<=n;i++)if(a[i].x==x&&a[i].y==y){cant=1;break;}
39         if(!cant)ans=get(x,y),sum=1;
40         else for(i=0;i<4;i++){
41             nowx=x+xx[i];nowy=y+yy[i];
42             tmp=get(nowx,nowy);if(tmp<ans)ans=tmp,sum=1;else if(tmp==ans)sum++;
43         }
44     }else{
45         sort(a+1,a+1+n,cmp1);x=a[n>>1].x;x1=a[n/2+1].x;
46         sort(a+1,a+1+n,cmp2);y=a[n>>1].y;y1=a[n/2+1].y;
47         ans=get(x,y);sum=(x1-x+1)*(y1-y+1);
48         for(i=1;i<=n;i++)if(a[i].x>=x&&a[i].x<=x1&&a[i].y>=y&&a[i].y<=y1)sum--;
49     }
50     printf("%d %d\n",ans,sum);
51     return 0;
52 }
View Code

 

bzoj 1916: [Usaco2010 Open]冲浪

  dp。按照拓扑顺序来。。f[i][j]表示从i点到n点,途中j次失误的最大愉悦值,val(i,j)表示i到j这条边的愉悦值。

  f[i][j]=min{ max{ f[k][j]+val(i,k) }(没失误),min{ f[k][j-1]+val(i,k) }(失误了= =) },(存在边i-->k)。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=50023;
 7 struct zs{
 8     int dis,too,pre;
 9 }e[150233],E[150233];
10 int last[maxn],cd[maxn],las[maxn];
11 ll f[maxn][11];
12 int dl[maxn],l,r,now,to;
13 int i,j,k,K,n,m,a,b,c;
14 int ra;char rx;
15 inline int read(){
16     rx=getchar();ra=0;
17     while(rx<'0'||rx>'9')rx=getchar();
18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
19 }
20 inline void ins(int a,int b,int c){
21     E[i].too=b;E[i].dis=c;E[i].pre=las[a];las[a]=i;
22 }
23 int main(){
24     n=read();m=read();K=read();
25     for(i=1;i<=m;i++)
26         a=read(),b=read(),e[i].dis=read(),e[i].too=a,e[i].pre=last[b],last[b]=i,cd[a]++,ins(a,b,e[i].dis);
27     //memset(f,255,sizeof(f));
28     r=1;dl[1]=n;f[n][0]=0;
29     while(l<r){
30         now=dl[++l];
31         for(i=last[now],to=e[i].too;i;i=e[i].pre,to=e[i].too){
32             cd[to]--;if(!cd[to])dl[++r]=to;
33             if(f[now][0]+e[i].dis>f[to][0])f[to][0]=f[now][0]+e[i].dis;
34         }
35     }
36 //  for(i=1;i<=n;i++)printf("  %d %lld\n",dl[i],f[dl[i]][0]);
37     for(i=2,now=dl[i];i<=n;now=dl[++i]){
38         for(j=las[now],to=E[j].too;j;j=E[j].pre,to=E[j].too)
39             for(k=1;k<=K;k++)if(f[to][k]+E[j].dis>f[now][k])f[now][k]=f[to][k]+E[j].dis;
40         for(j=las[now],to=E[j].too;j;j=E[j].pre,to=E[j].too)
41             for(k=1;k<=K;k++)if(f[to][k-1]+E[j].dis<f[now][k])f[now][k]=f[to][k-1]+E[j].dis;
42 //      for(j=0;j<=K;j++)printf("  %d %d: %lld\n",now,j,f[now][j]);
43     }
44     printf("%lld\n",f[1][K]);
45     return 0;
46 }
View Code

 

bzoj 1751: [Usaco2005 qua]Lake Counting

  如题。。联通块计数。。注意是八连通= =

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=102;
 6 int map[maxn*maxn];
 7 int xx[8]={1,1,1,0,0,-1,-1,-1},yy[8]={-1,0,1,-1,1,-1,0,1};
 8 int fa[maxn*maxn];
 9 int i,j,k,n,m,x,y,nowx,nowy,tmpx,tmpy,tmp,now,ans;
10 int ra;char rx;
11 inline int read(){
12     rx=getchar();ra=0;
13     while(rx<'0'||rx>'9')rx=getchar();
14     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
15 }
16 int getfa(int x){
17     if(fa[x]!=x)fa[x]=getfa(fa[x]);
18     return fa[x];
19 }
20 int main(){
21     n=read();m=read();
22     for(i=1;i<=n;i++)for(j=1;j<=m;j++){
23         for(rx=getchar();rx!='.'&&rx!='W';rx=getchar());
24         map[(i-1)*m+j]=(rx=='W')?2:1;
25         fa[(i-1)*m+j]=(i-1)*m+j;
26     }
27     for(i=1;i<=n;i++)for(j=1;j<=m;j++){
28         tmp=(i-1)*m+j;
29         if(map[tmp]!=2)continue;
30         for(k=0;k<8;k++){
31             nowx=i+xx[k];nowy=j+yy[k];
32             if(nowx<1||nowy<1||nowx>n||nowy>m)continue;
33             now=(nowx-1)*m+nowy;
34             if(map[now]!=2)continue;
35             x=getfa(tmp);y=getfa(now);
36             if(x!=y)fa[y]=x;
37         }
38     }
39     for(i=n*m;i;i--)if(map[i]==2&&fa[i]==i)ans++;
40     printf("%d\n",ans);
41     return 0;
42 }
View Code

 

bzoj 1914: [Usaco2010 OPen]Triangle Counting 数三角形

  极角排序一下。。http://www.cnblogs.com/czllgzmzl/p/5071114.html

 

bzoj 1590: [Usaco2008 Dec]Secret Message 秘密信息

  好久没写trie了。。。注意在trie树上得记录两个信息:在当前节点结束的信息数量;在当前节点还没结束的信息数量。。

  每次查找的答案就是  路径上已经结束的数量+最后那个节点上还没结束的信息数量。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int maxn=500023;
 6 int map[maxn][4],len,tot,tmp;
 7 int i,j,k,n,m,now,ans;
 8 int ra;char rx;
 9 inline int read(){
10     rx=getchar();ra=0;
11     while(rx<'0'||rx>'9')rx=getchar();
12     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
13 }
14 int main(){
15     n=read();m=read();
16     for(i=1;i<=n;map[now][3]++,i++)
17         for(now=0,len=read();len;len--){
18             for(rx=getchar();rx!='0'&&rx!='1';rx=getchar());tmp=rx-48;
19             if(!map[now][tmp])map[now][tmp]=++tot,now=tot;else now=map[now][tmp];
20             if(len>1)map[now][2]++;
21         }
22     for(i=1;i<=m;printf("%d\n",ans+map[now][2]),i++)
23         for(now=ans=0,len=read();len;len--){
24             for(rx=getchar();rx!='0'&&rx!='1';rx=getchar());tmp=rx-48;
25             now=map[now][tmp];ans+=map[now][3];
26             if(!now){while(--len)for(rx=getchar();rx!='0'&&rx!='1';rx=getchar());break;}
27         }
28     return 0;
29 }
View Code

 

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

  边双联通分量。。先把边双连通分量缩点,就变成如何使一棵树上两两节点间有多条路可走。。。答案就是(叶子节点数量+1)/2。

  求边双连通分量时,记录一下当前点的父亲边,如果low[x]==dfn[x],那么点x的父亲边就是桥。把桥都从原图中去掉,剩下的就是一坨边双联通分量了。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=1005;
 6 struct zs{
 7     int too,pre;
 8 }e[20023];
 9 int last[maxn],tot=1;
10 bool isbridge[20023];
11 int dfn[maxn],low[maxn],tim;
12 int degree[maxn],bel[maxn],blocknum;
13 int i,j,k,n,m,a,b,ans;
14  
15 int ra;char rx;
16 inline int read(){
17     rx=getchar();ra=0;
18     while(rx<'0'||rx>'9')rx=getchar();
19     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
20 }
21 void tarjan(int x,int preedge){
22     int i,to;dfn[x]=low[x]=++tim;
23     for(i=last[x],to=e[i].too;i;i=e[i].pre,to=e[i].too)if((i^1)!=preedge)
24         if(!dfn[to])tarjan(to,i),low[x]=low[x]>low[to]?low[to]:low[x];
25         else low[x]=low[x]>dfn[to]?dfn[to]:low[x];
26     if(preedge&&low[x]==dfn[x])isbridge[preedge]=isbridge[preedge^1]=1;
27 }
28 inline void insert(int a,int b){
29     e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;
30     e[++tot].too=a;e[tot].pre=last[b];last[b]=tot;
31 }
32 void rebuild(int x,int num){
33     bel[x]=num;
34     for(int i=last[x];i;i=e[i].pre)if(!isbridge[i]&&!bel[e[i].too])rebuild(e[i].too,num);
35 }
36 int main(){
37     n=read();m=read();
38     for(i=1;i<=m;i++)a=read(),b=read(),insert(a,b);
39     for(i=1;i<=n;i++)if(!dfn[i])tarjan(i,0);
40     for(i=1;i<=n;i++)if(!bel[i])rebuild(i,++blocknum);
41     for(i=2;i<=tot;i+=2)if(isbridge[i])degree[bel[e[i].too]]++,degree[bel[e[i^1].too]]++;
42     for(i=1;i<=blocknum;i++)if(degree[i]==1)ans++;
43     printf("%d\n",(ans+1)>>1);
44     return 0;
45 }
View Code

 

bzoj 1693: [Usaco2007 Demo]Asteroids

  盯了半天英文题面。。。结果发现双倍经验。同bzoj1741。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=503;
 6 struct zs{
 7     int too,pre;
 8     bool flow;
 9 }e[22333];
10 int last[maxn<<1],u[maxn<<1],dl[maxn<<1];
11 short dis[maxn<<1];
12 int i,j,k,n,m,tot,s,t,a,b,ans;
13 int ra;char rx;
14 inline int read(){
15     rx=getchar();ra=0;
16     while(rx<'0'||rx>'9')rx=getchar();
17     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
18 }
19 inline void insert(int a,int b){
20     e[++tot].too=b;e[tot].flow=1;e[tot].pre=last[a];last[a]=tot;
21     e[++tot].too=a;e[tot].flow=0;e[tot].pre=last[b];last[b]=tot;
22 }
23 inline bool bfs(){
24     memset(dis,255,(t+1)<<1);
25     int l=0,r=1,now,i;dl[1]=s;dis[s]=0;
26     while(l<r){
27         now=dl[++l];
28         for(i=last[now];i;i=e[i].pre)if(dis[e[i].too]==-1&&e[i].flow)
29             dis[e[i].too]=dis[now]+1,dl[++r]=e[i].too;
30     }
31     return dis[t]!=-1;
32 }
33 int dfs(int x,int mx){
34     if(x==t)return mx;
35     int i,used=0,w;
36     for(i=last[x];i;i=e[i].pre)if(e[i].flow&&dis[e[i].too]==dis[x]+1){
37         w=dfs(e[i].too,1);if(w){
38             e[i].flow=0;;e[i^1].flow=1;
39             used++;if(used==mx)return mx;
40         }
41     }
42     dis[x]=-1;return used;
43 }
44 int main(){tot=1;
45     n=read();m=read();s=0;t=n+n+1;
46     for(i=1;i<=n;i++)insert(s,i),insert(i+n,t);
47     for(i=1;i<=m;i++)
48         a=read(),b=read(),insert(a,b+n);
49     while(bfs())ans+=dfs(s,2333333);
50     printf("%d\n",ans);
51     return 0;
52 }
View Code

 

bzoj 1716: [Usaco2006 Dec]The Fewest Coins 找零钱

  搜题解的话应该连题目名字一起搜。。因为也是poj3260。

  店家找钱一定不超过v_max^2。。。因为这就意味着John多给店主硬币超过了v_max个。。想要让这些硬币无法用v_max的硬币替代掉一部分,则它们不同组合的价值和对v_max取模后都各不相同。。。。总之根据抽屉原理这是不可能的。。。

  所以对店家跑个无限背包,对john跑个有限背包就行了。

UPD:。。。。。。。。。。。。。。。。。。。论傻逼不好好想题就跑去看题解的危害性。

    根据KPM代码可得。。店家找钱一定不超过v_max。。。其实这也是很显然的?(捂脸。。然而为何我想不到)。。找钱超过v_max肯定有硬币是脑残多给的啊。。。

    不过更加不科学的是。。。我数组开大反而快了不少。。。。而且是多次试验确定不是测评姬看脸= =。。。。导演这和说好的不一样。。。

    数组开2w+就#1了。。。开1w+就慢了快一倍TAT。。。感人肺腑

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=102<<4;
 7 const int inf=800233333;
 8 struct zs{
 9     int c,v;
10 }a[maxn];
11 int f[25233],owner[15233];
12 int c[102],v[102];
13 int i,j,k,n,m,ans,mx,N;
14 int ra;char rx;
15 inline int read(){
16     rx=getchar();ra=0;
17     while(rx<'0'||rx>'9')rx=getchar();
18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
19 }
20 bool cmp(zs a,zs b){
21     return a.v<b.v;
22 }
23 int main(){
24     n=read();m=read();
25     for(i=1;i<=n;i++)v[i]=read(),mx=max(mx,v[i]);
26     for(i=1;i<=n;i++)c[i]=read();
27 //  mx*=mx;
28     for(i=1;i<=n;i++){
29         for(j=1;j<=c[i];j<<=1)a[++N].c=j,a[N].v=j*v[i],c[i]-=j;
30         if(c[i])j=c[i],a[++N].c=j,a[N].v=j*v[i];
31     }
32     sort(a+1,a+1+N,cmp);
33     while(N&&a[N].v>mx+m)N--;
34 //  for(i=1;i<=N;i++)printf("    %d %d\n",a[i].c,a[i].v);
35     memset(owner,50,(mx+1)<<2);
36     memset(f,50,(mx+1+m)<<2);owner[0]=f[0]=0;
37     for(i=1;i<=n;i++)for(j=v[i];j<=mx;j++)if(owner[j]>owner[j-v[i]]+1)owner[j]=owner[j-v[i]]+1;
38 //  for(i=1;i<=20;i++)printf("    %d %d\n",i,owner[i]);
39     for(i=1;i<=N;i++)for(j=mx+m;j>=a[i].v;j--)
40         if(f[j]>f[j-a[i].v]+a[i].c)f[j]=f[j-a[i].v]+a[i].c;
41     ans=inf;
42     for(j=mx+m;j>=m;j--)if(f[j]+owner[j-m]<ans)ans=f[j]+owner[j-m];
43     if(ans==inf)printf("-1\n");else printf("%d\n",ans);
44     return 0;
45 }
View Code

 

bzoj 2199: [Usaco2011 Jan]奶牛议会

  2-SAT问题。。。这类问题似乎没法怎么包装。。。对于每头奶牛,如果它的某票没实现的话,另一票一定要实现。。。

  因为有的议案结局未定。。而且数据范围不大。。直接暴力上。。。时间复杂度O(nm)

  不知道如果缩点后搞的话怎么处理那些未定的议案TAT

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=1023;
 6 struct zs{
 7     int too,pre;
 8 }e[8233];
 9 int last[maxn<<1],a,b;
10 bool must[maxn<<1];
11 int i,j,k,n,m,tot;
12 char ans[maxn];
13 int ra;char rx,x1,x2;
14 bool can0,can1;
15 inline int read(){
16     rx=getchar();ra=0;
17     while(rx<'0'||rx>'9')rx=getchar();
18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
19 }
20 inline void insert(int a,int b){
21     e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;
22 }
23 void dfs(int x){
24     must[x]=1;if(must[x>n?x-n:x+n])return;
25     for(int i=last[x];i;i=e[i].pre)if(!must[e[i].too])dfs(e[i].too);
26 }
27 inline bool judge(int x){
28     memset(must,0,(n+n+1));
29     dfs(x);
30     for(int i=n;i;i--)if(must[i]&&must[i+n])return 0;
31     return 1;
32 }
33 int main(){
34     n=read();m=read();
35     for(i=1;i<=m;i++){
36         a=read();for(x1=getchar();x1!='Y'&&x1!='N';x1=getchar());
37         if(x1=='N')a+=n;
38         b=read();for(x2=getchar();x2!='Y'&&x2!='N';x2=getchar());
39         if(x2=='N')b+=n;
40         insert(a>n?a-n:a+n,b);insert(b>n?b-n:b+n,a);
41     }
42     for(i=1;i<=n;i++){
43         can0=judge(i);
44         can1=judge(i+n);
45         if(can0&&can1)ans[i]='?';
46         else if(can0)ans[i]='Y';
47         else if(can1)ans[i]='N';
48         else {puts("IMPOSSIBLE");return 0;}
49     }
50     for(i=1;i<=n;i++)putchar(ans[i]);printf("\n");
51     return 0;
52 }
View Code

 

bzoj 1712: [Usaco2007 China]Summing Sums 加密

  矩阵乘法。。。由题目得出,Ci'=sum-Ci,(sum表示前一轮中奶牛数字和)。本轮结束后sum'=sum*n-sum。

  构造矩阵。。一个n行2列的矩阵A,第i行第一列为Ci,第二列为sum。

  第二个矩阵B为2*2的矩阵,第一行为-1,0;第二行为1,(n-1)。

  为啥卡了半天常数还是那么慢TAT

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #define ll long long
 5 using namespace std;
 6 const ll modd=98765431;
 7 const int maxn=50233;
 8 ll pow[2][2],b[2][2],a[maxn][2];
 9 int i,j,k,n,m,T;
10 int ra;char rx;
11 inline int read(){
12     rx=getchar();ra=0;
13     while(rx<'0'||rx>'9')rx=getchar();
14     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
15 }
16 inline void mul1(ll a[2][2],ll b[2][2]){
17     ll c[2][2];int i,j,k;
18     for(i=0;i<2;i++)for(j=0;j<2;j++)
19     for(c[i][j]=0,k=0;k<2;k++){c[i][j]+=a[i][k]*b[k][j];if(c[i][j]>=modd)c[i][j]%=modd;}
20     for(i=0;i<2;i++)for(j=0;j<2;j++)a[i][j]=c[i][j];
21 }
22 inline void mul2(ll a[maxn][2],ll b[2][2]){
23     ll c[maxn][2];i,j,k;
24     for(i=0;i<n;i++)for(j=0;j<2;j++)
25     for(c[i][j]=0,k=0;k<2;k++){c[i][j]+=a[i][k]*b[k][j];if(c[i][j]>=modd)c[i][j]%=modd;}
26     for(i=0;i<n;i++)for(j=0;j<2;j++)a[i][j]=c[i][j];
27 }
28 int main(){
29     n=read();T=read();
30     for(i=0;i<n;i++)a[i][0]=read(),a[0][1]+=a[i][0],a[0][1]-=a[0][1]>=modd?modd:0;
31     for(i=1;i<n;i++)a[i][1]=a[0][1];
32     pow[0][0]=pow[1][1]=1;
33     b[0][0]=-1;b[0][1]=0;b[1][0]=1;b[1][1]=n-1;
34     while(T){
35         if(T&1)
36             mul1(pow,b);
37         T>>=1;if(T)mul1(b,b);
38     }
39     mul2(a,pow);
40     for(i=0;i<n;i++)printf("%lld\n",(a[i][0]+modd)%modd);
41     return 0;
42 }
View Code

 

bzoj 1583: [Usaco2009 Mar]Moon Mooing 哞哞叫

  首先根据题目给出的式子,两种方式叫声时长都是递增的。。就变成了在两个递增的数列中取出前n小的。。

  可以无脑的分别求出两种叫法的前n项再合并。。。。也可以只记录当前两种叫法分别叫到了多长时间,每次选下一次叫时间短的加入答案(因为可以当前项算出后一项时长)。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=4002333;
 7 int i,j,k,n,m,l1,l2,r;
 8 ll c,a1,a2,c1,c2,b1,b2;
 9 ll now,tmp1,tmp2,dl[maxn];
10 int ra;char rx;
11 inline int read(){
12     rx=getchar();ra=0;
13     while(rx<'0'||rx>'9')rx=getchar();
14     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
15 }
16 int main(){
17     c=read();n=read();
18     a1=read();b1=read();c1=read();
19     a2=read();b2=read();c2=read();
20     l1=l2=1;r=1;dl[1]=c;tmp1=c*a1/c1+b1;tmp2=c*a2/c2+b2;
21     while(r<n){
22         if(tmp1<tmp2){
23             if(tmp1!=dl[r])dl[++r]=tmp1;
24             tmp1=dl[++l1]*a1/c1+b1;
25         }else{
26             if(tmp2!=dl[r])dl[++r]=tmp2;
27             tmp2=dl[++l2]*a2/c2+b2;
28         }
29     }
30     printf("%lld\n",dl[r]);
31     return 0;
32 }
View Code

 

bzoj 1731: [Usaco2005 dec]Layout 排队布局

  差分约束。。http://www.cnblogs.com/czllgzmzl/p/5072819.html

 

bzoj 2099: [Usaco2010 Dec]Letter 恐吓信

  字符串。因为原信件里同一段内容可以多次截取。。所以每次剪出最长公共前缀就可以使总的剪裁次数最小。

  求出后缀数组后,每次二分找lcp。。。时间复杂度(nlogn+mlogn*比较字符串大小的时间复杂度)(实际复杂度远低于最坏情况。。。比较字符串大小可以直接暴力)

  注意一下二分的左边界(取决于具体写法= =)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ll long long
 6 using namespace std;
 7 const ll modd=223333333;
 8 const int maxn=50233;
 9 int i,j,k,n,m,l,r,mid,now,pos,ans,samelen,L,R,MID;
10 ll pre[maxn],pre1[maxn],jc[maxn],val1,val2;
11 int sa[maxn];
12 char s[maxn],s1[maxn];
13 int ra;char rx;
14 inline int read(){
15     rx=getchar();ra=0;
16     while(rx<'0'||rx>'9')rx=getchar();
17     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
18 }
19 inline int getlen(int s1,int s2){
20     if(s[s1]!=s[s2])return 0;
21     l=1;r=n-(s1<s2?s2:s1)+1;
22     val1=pre[s1+r-1]-pre[s1-1]*jc[r]%modd;if(val1<0)val1+=modd;
23     val2=pre[s2+r-1]-pre[s2-1]*jc[r]%modd;if(val2<0)val2+=modd;
24     if(val1==val2)return r;r--;
25     while(l<r){
26         mid=(l+r+1)>>1;
27         val1=pre[s1+mid-1]-pre[s1-1]*jc[mid]%modd;if(val1<0)val1+=modd;
28         val2=pre[s2+mid-1]-pre[s2-1]*jc[mid]%modd;if(val2<0)val2+=modd;
29         if(val1!=val2)r=mid-1;else l=mid;
30     }
31     return l;
32 }
33 bool cmp(int a,int b){
34     now=getlen(a,b);
35     return s[a+now]<s[b+now];
36 }
37 inline int get1(int l1,int l2){
38     if(s[l1]!=s1[l2])return 0;
39     l=1;r=min(n-l1,m-l2)+1;
40     val1=pre[l1+r-1] -pre[l1-1] *jc[r]%modd;if(val1<0)val1+=modd;
41     val2=pre1[l2+r-1]-pre1[l2-1]*jc[r]%modd;if(val2<0)val2+=modd;
42     if(val1==val2)return r;r--;
43     while(l<r){
44         mid=(l+r+1)>>1;
45         val1=pre[l1+mid-1] -pre[l1-1] *jc[mid]%modd;if(val1<0)val1+=modd;
46         val2=pre1[l2+mid-1]-pre1[l2-1]*jc[mid]%modd;if(val2<0)val2+=modd;
47         if(val1!=val2)r=mid-1;else l=mid;
48 //      printf("%d    %d-%d %lld      %d-%d %lld\n",mid,l1,l1+mid-1,val1,l2,l2+mid-1,val2);
49     }
50     return l;
51 }
52 inline bool bigger(int l1,int l2){
53     now=get1(l1,l2);
54     if(now>samelen)samelen=now;
55 //  for(int i=l1;i<=n;i++)putchar(s[i]);putchar('|');for(int i=l2;i<=m;i++)putchar(s1[i]);printf("  %d\n",now);
56     return s[l1+now]>s1[l2+now];
57 }
58 int main(){
59     n=read();m=read();s[n+1]=0;s1[m+1]=1;
60     for(jc[0]=1,i=1;i<=n;pre[i]=(pre[i-1]*(ll)197+(ll)s[i])%modd,jc[i]=jc[i-1]*197%modd,i++)for(s[i]=getchar();s[i]<'A'||s[i]>'Z';s[i]=getchar());
61     for(i=1;i<=m;pre1[i]=(pre1[i-1]*(ll)197+(ll)s1[i])%modd,i++)for(s1[i]=getchar();s1[i]<'A'||s1[i]>'Z';s1[i]=getchar());
62 //  for(i=1;i<=n;i++)printf("%lld    ",pre[i]);printf("\n");
63 //  for(i=1;i<=m;i++)printf("%lld    ",pre1[i]);printf("\n");
64      
65     for(i=1;i<=n;i++)sa[i]=i;
66     sort(sa+1,sa+1+n,cmp);
67 //  for(i=1;i<=n;i++)printf("%d\n",sa[i]);
68 //  for(i=1;i<=n;i++)printf("  %d\n",sa[i]);
69     for(pos=1;pos<=m;now=samelen=0){
70         L=1;R=n;
71         while(L<=R){
72             MID=(L+R)>>1;
73             if(bigger(sa[MID],pos))R=MID-1;else L=MID+1;
74         }
75     //  for(i=sa[L];i<=n;i++)putchar(s[i]);printf("\n");
76         if(samelen<m-pos+1&&L<n)samelen=max(samelen,get1(sa[L+1],pos));
77         ans++;pos+=samelen;//printf("          %d\n",pos);
78     }
79     printf("%d\n",ans);
80     return 0;
81 }
View Code

 

bzoj 1577: [Usaco2009 Feb]庙会捷运Fair Shuttle

  把奶牛按目的地升序排序,然后直接依次尽量满足。。正确性同bzoj1828.。。。

  具体用线段树实现(区间加&&查询区间最小值)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 #include<algorithm>
 6 using namespace std;
 7 const int maxn=20233;
 8 struct zs{
 9     int t,s,num;
10 }a[50233];
11 int l[maxn<<1],r[maxn<<1],mn[maxn<<1],mid[maxn<<1],del[maxn<<1];
12 int i,j,k,n,m,c,num,ans,tot;
13 int ra;char rx;
14 inline int read(){
15     rx=getchar();ra=0;
16     while(rx<'0'||rx>'9')rx=getchar();
17     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
18 }
19 void build(int a,int b){
20     int now=++tot;mn[now]=c;
21     mid[now]=(a+b)>>1;
22     if(a<b){
23         l[now]=tot+1;build(a,mid[now]);
24         r[now]=tot+1;build(mid[now]+1,b);
25     }
26 }
27 inline void pushdown(int now,int l,int r){
28     del[l]+=del[now];del[r]+=del[now];
29     mn[l]-=del[now];mn[r]-=del[now];del[now]=0;
30 }
31 void insert(int now,int a,int b,int c,int d,int num){
32     if(c<=a&&d>=b){del[now]+=num,mn[now]-=num;return;}
33     if(del[now])pushdown(now,l[now],r[now]);
34     if(c<=mid[now])insert(l[now],a,mid[now],c,d,num);
35     if(d>mid[now])insert(r[now],mid[now]+1,b,c,d,num);
36     mn[now]=mn[l[now]]<mn[r[now]]?mn[l[now]]:mn[r[now]];
37 }
38 int query(int now,int a,int b,int c,int d){
39     if(c<=a&&d>=b)return mn[now];
40     if(del[now])pushdown(now,l[now],r[now]);
41     int tmp=233333333;
42     if(c<=mid[now])tmp=query(l[now],a,mid[now],c,d);
43     if(d>mid[now])tmp=min(tmp,query(r[now],mid[now]+1,b,c,d));
44     return tmp;
45 }
46 bool cmp(zs a,zs b){return a.t<b.t;}
47 int main(){
48     m=read();n=read();c=read();
49     for(i=1;i<=m;i++)a[i].s=read(),a[i].t=read()-1,a[i].num=read();
50     build(1,n);
51     sort(a+1,a+1+m,cmp);
52     for(i=1;i<=m;i++)num=min(a[i].num,query(1,1,n,a[i].s,a[i].t)),insert(1,1,n,a[i].s,a[i].t,num),ans+=num;
53     printf("%d\n",ans);
54     return 0;
55 }
View Code

 

bzoj 2274: [Usaco2011 Feb]Generic Cow Protests

  dp优化。。f[i]表示划分前i个数的方案总数。。f[0]=1;f[i]=sum{ f[j] },(j<i且presum[i]>=presum[j])(presum表示前缀和)

  所以把presum排序后,按原顺序算。。就是求排序后的前缀和。树状数组还是线段树什么的随意啦。。结果写的sgt比kpm的树状数组慢了三分之一= =

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=132333;
 7 const int modd=1000000009;
 8 int sum[maxn<<1],rk[100233],pos[100233],pre[100233],a[100233],f[100233];
 9 int i,j,k,n,m,x,size,tot;
10 int ra,fh;char rx;
11 inline int read(){
12     rx=getchar();ra=0;fh=1;
13     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
14     if(rx=='-')fh=-1,rx=getchar();
15     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
16 }
17 bool cmp(int aa,int b){return pre[aa]<pre[b];}
18 int main(){
19     n=read();
20     for(i=1;i<=n;rk[i]=i,pre[i]=pre[i-1]+a[i],i++)a[i]=read();
21     sort(rk+1,rk+1+n,cmp);for(i=1;i<=n;i++)tot+=(pre[rk[i]]!=pre[rk[i-1]])||i==1,pos[rk[i]]=tot;
22     size=1;while(size<tot)size<<=1;size--;
23     for(i=1;i<=n;i++){
24         for(x=pos[i]+size,f[i]=sum[x]+(pre[i]>=0);(x&(-x))!=x;x>>=1)if(x&1){f[i]+=sum[x^1];if(f[i]>=modd)f[i]-=modd;}
25         for(x=pos[i]+size;x;x>>=1){sum[x]+=f[i];if(sum[x]>=modd)sum[x]-=modd;}
26     }
27     printf("%d\n",f[n]);
28     return 0;
29 }
View Code

 

bzoj 1594: [Usaco2008 Jan]猜数游戏

  二分答案+并查集判定 http://www.cnblogs.com/czllgzmzl/p/5074066.html

 

bzoj 1744: [Usaco2005 oct]Skiing 奶牛滑雪

  最短路。。看了kpm代码才发现倒着跑会方便一些。。速度的变化就好弄了。。就是把后面的路径(耗时)长度都乘上速度的变化。。。

  假设初始速度为1,最后把时间除以真正的初始速度就好了

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 #include<algorithm>
 6 using namespace std;
 7 const int maxn=20233;
 8 int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0};
 9 int dlx[502333],dly[502333];
10 int map[103][103];
11 double tmpdis,v0,dis[103][103],nowdis;
12 double two[51];
13 bool u[103][103];
14 int i,j,k,n,m,c,ans,l,r,x,y,nowx,nowy;
15 int ra,fh;char rx;
16 inline int read(){
17     rx=getchar();ra=0;fh=1;
18     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
19     if(rx=='-')fh=-1,rx=getchar();
20     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
21 }
22 inline double get(double x,int delta){
23     if(delta>=0)return x*two[delta];
24     return x/two[-delta];
25 }
26 int main(){
27     for(two[0]=1.0,i=1;i<=50;i++)two[i]=two[i-1]*2.0;
28     double inf=1<<30;inf*=inf;
29     v0=read();n=read();m=read();
30     for(i=1;i<=n;i++)for(j=1;j<=m;j++)map[i][j]=read(),dis[i][j]=inf;
31     dis[n][m]=0.0;
32     dlx[1]=n;dly[1]=m;l=0;r=1;u[n][m]=1;
33     while(l<r){
34         nowx=dlx[++l];nowy=dly[l];nowdis=dis[nowx][nowy];
35         for(i=0;i<4;i++){
36             x=nowx+xx[i];y=nowy+yy[i];
37             if(x<1||x>n||y<1||y>m)continue;
38             tmpdis=get(nowdis,map[nowx][nowy]-map[x][y])+1.0;
39             if(tmpdis<dis[x][y])
40                 if(!u[x][y])dis[x][y]=tmpdis,dlx[++r]=x,dly[r]=y,u[x][y]=1;
41                 else dis[x][y]=tmpdis;
42         }
43         u[nowx][nowy]=0;
44     }
45     printf("%.2lf\n",dis[1][1]/v0);
46     return 0;
47 }
View Code

 

bzoj 1663: [Usaco2006 Open]赶集

  最长路。。如果接完一个点的礼物后还来得及去另外的一个点接礼物,就在这两点间连条单向边。

  因为出发时不一定要等点1的礼物,所以新建一个点0,与出发时能赶去接礼物的点连边 。最后答案就是最长路长度了

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 #include<algorithm>
 6 using namespace std;
 7 const int maxn=402;
 8 struct zs{
 9     int too,pre;
10 }e[160433];
11 int last[maxn],dis[maxn],dl[23333],tim[maxn];
12 int i,j,k,n,m,ans,l,r,tot,b,s,now,to;
13 bool u[maxn];
14 int ra;char rx;
15 inline int read(){
16     rx=getchar();ra=0;
17     while(rx<'0'||rx>'9')rx=getchar();
18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
19 }
20 inline void insert(int a,int b){
21     e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;
22 }
23 int main(){
24     n=read();
25     for(i=1;i<=n;i++)tim[i]=read();
26     for(i=1;i<=n;i++)for(j=1;j<=n;j++){
27         b=read();
28         if(i!=j&&tim[j]-tim[i]>=b)insert(i,j);
29         if(i==1&&tim[j]>=b)insert(0,j);
30     }
31     s=0;u[s]=1;l=0;r=1;dl[1]=s;dis[s]=0;
32     while(l<r){
33         now=dl[++l];
34         for(i=last[now],to=e[i].too;i;i=e[i].pre,to=e[i].too)if(dis[to]<dis[now]+1)
35             if(!u[to])u[to]=1,dl[++r]=to,dis[to]=dis[now]+1;
36             else dis[to]=dis[now]+1;
37         u[now]=0;
38     }
39     for(i=1;i<=n;i++)if(dis[i]>ans)ans=dis[i];
40     printf("%d\n",ans);
41     return 0;
42 }
View Code

 

bzoj 1735: [Usaco2005 jan]Muddy Fields 泥泞的牧场

  二分图最大匹配。类似1741小行星那题。。不同的是多了个约束条件,木板只能在泥地里放。

  先按行处理出各泥地的编号(同一行且联通的泥地算同个点),列的时候同理

  对于每个泥泞的点,把它所在的行编号和所在的列编号这两点间连边。。最后求二分图最大匹配

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=26*50*2+2;
 6 struct zs{
 7     int too,pre;
 8     bool flow;
 9 }e[202333];
10 int last[maxn],dis[maxn],s,t,tot=1;
11 int dl[maxn];
12 int bell[51][51],belh[51][51],lnum,hnum;
13 int i,j,k,n,m,ans;
14 char map[51][51];
15 bool u[maxn];
16 int ra;char rx;
17 inline int read(){
18     rx=getchar();ra=0;
19     while(rx<'0'||rx>'9')rx=getchar();
20     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
21 }
22 inline bool bfs(){
23     int l=0,r=1,now,i;
24     memset(dis,255,(t+1)<<2);dis[s]=0;dl[1]=s;
25     while(l<r){
26         now=dl[++l];
27         for(i=last[now];i;i=e[i].pre)if(dis[e[i].too]==-1&&e[i].flow)
28         dl[++r]=e[i].too,dis[e[i].too]=dis[now]+1;
29     }
30     return dis[t]!=-1;
31 }
32 int dfs(int x,int mx){
33     if(x==t)return mx;
34     int used=0,i,w,to;
35     for(i=last[x],to=e[i].too;i;i=e[i].pre,to=e[i].too)if(e[i].flow&&dis[to]==dis[x]+1){
36         w=dfs(e[i].too,1);if(w){
37             e[i].flow=0;e[i^1].flow=1;
38             used++;
39             if(used==mx)return mx;
40         }
41     }
42     dis[x]=-1;return used;
43 }
44 inline void insert(int a,int b){
45     e[++tot].too=b;e[tot].flow=1;e[tot].pre=last[a];last[a]=tot;
46     e[++tot].too=a;e[tot].flow=0;e[tot].pre=last[b];last[b]=tot;
47 }
48 int main(){
49     n=read();m=read();
50     for(i=1;i<=n;i++)for(j=1;j<=m;j++)for(map[i][j]=getchar();map[i][j]!='*'&&map[i][j]!='.';map[i][j]=getchar());
51     for(i=1;i<=n;i++)
52         for(j=1;j<=m;j++)if(map[i][j]=='*'){
53             if(map[i][j-1]!='*')hnum++;
54             belh[i][j]=hnum;
55     }lnum=hnum;
56     for(j=1;j<=m;j++)for(i=1;i<=n;i++)if(map[i][j]=='*'){
57         if(map[i-1][j]!='*')lnum++;
58         bell[i][j]=lnum;
59     }
60     for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(map[i][j]=='*')insert(belh[i][j],bell[i][j]);
61     s=0;t=lnum+1;
62     for(i=1;i<=hnum;i++)insert(s,i);for(i=hnum+1;i<=lnum;i++)insert(i,t);
63     while(bfs())ans+=dfs(s,233333333);
64     printf("%d\n",ans);
65     return 0;
66 }
View Code

 

bzoj 2196: [Usaco2011 Mar]Brownie Slicing

  二分答案+判定。。。。

  JSZX11556:我随手写的怎么就#1了。。。。不过后来kpm压常抢了#1.。%%%

   二分答案设为mid。。判定就是看是否能分出A段连续的行,每一段里面竖着分成B份,使得每一份都>=mid。划分的时候都贪心地试就行了。。。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=503;
 6 int map[maxn][maxn],a[maxn];
 7 int i,j,k,n,m,sum,A,B,l,r,mid;
 8 int ra;char rx;
 9 inline int read(){
10     rx=getchar();ra=0;
11     while(rx<'0'||rx>'9')rx=getchar();
12     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
13 }
14 inline bool can(int h,int x){
15     register int i;int sum=0,num=0;
16     for(i=1;i<=m;i++)a[i]+=map[h][i];
17     for(i=1;i<=m&&sum<B;i++){
18         num+=a[i];
19         if(num>=x)num=0,sum++;
20     }
21     return sum>=B;
22 }
23 inline bool judge(int x){
24     sum=0;
25     memset(a,0,(m+1)<<2);
26     for(i=1;i<=n&&sum<A;i++)if(can(i,x))sum++,memset(a,0,(m+1)<<2);
27     return sum>=A;
28 }
29 int main(){
30     n=read();m=read();A=read();B=read();
31     for(i=1;i<=n;i++)for(j=1;j<=m;j++)map[i][j]=read(),r+=map[i][j];
32     l=1;r/=(A*B);
33     while(l<r){
34         mid=(l+r+1)>>1;
35         if(judge(mid))l=mid;else r=mid-1;
36     }
37     printf("%d\n",l);
38     return 0;
39 }
View Code

 

bzoj 2059: [Usaco2010 Nov]Buying Feed 购买饲料

  数据范围是n<=500,k<=10000。。dp+单调队列优化

  f[i][j]表示到第i个商店后,车上有j吨饲料的最小花费。

  f[i][j]=min{ f[i-1][k]+dis(i-1,i)*k^2+cost[i]*(j-k) },(k<=j,dis表示两点间距离,cost[i]表示商店i的饲料价格)

  也就是f[i][j]=cost[i]*j + min{ f[i-1][k]+dis(i-1,i)*k^2-cost[i]*k }。后面那个就可以用单调队列优化了。。

  偷懒调了优先队列。。多了个log果然慢成狗= =。。一开始脑残wa了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<queue>
 6 #define ll long long
 7 using namespace std;
 8 const int maxn=100005;
 9 const int maxk=200023;
10 ll f[maxk];
11 struct zs{
12     int k;ll val;
13 };
14 struct poi{
15     int pos,rest,cost;
16 }a[maxn];
17 int i,j;
18 ll n,m,K,ed;
19  
20 int ra,fh;char rx;
21 inline int read(){
22     rx=getchar();ra=0;fh=1;
23     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
24     if(rx=='-')rx=getchar(),fh=-1;
25     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
26 }
27  
28 bool cmp(poi a,poi b){return a.pos<b.pos;}
29 bool operator <(zs a,zs b){
30     return a.val>b.val;
31 }
32 int main(){
33     K=read();ed=read();n=read();
34     for(i=1;i<=n;i++)a[i].pos=read(),a[i].rest=read(),a[i].cost=read();
35     sort(a+1,a+1+n,cmp);
36     memset(f,50,(K+1)<<3);f[0]=0;
37     for(i=1;i<=n;i++){
38         priority_queue<zs>q;
39         while(!q.empty())q.pop();
40         ll dis=a[i].pos-a[i-1].pos;
41         q.push((zs){0,0});
42         for(j=1;j<=K;j++){
43             q.push((zs){j,f[j]-(ll)j*a[i].cost+dis*j*j});
44             while(!q.empty()&&q.top().k<j-a[i].rest)q.pop();
45             f[j]=q.top().val+(ll)j*a[i].cost;
46         }
47     }
48     printf("%lld\n",f[K]+(ll)(ed-a[n].pos)*K*K);
49     return 0;
50 }
View Code

 

bzoj 1777: [Usaco2010 Hol]rocks 石头木头

  博弈论。。。求当前局面的sg值

  如果不考虑每次取的数量的限制的话这题就是个阶梯nim(以深度为阶梯)。。。只考虑把石头从奇数深度挪到偶数深度。(根节点深度为0)

  但是有L的限制。。对每个奇数深度的节点就变成俩人轮流取,一次最多取L个。。。sg值就是石头数量对(L+1)取模后的值。。。偶数深度的节点sg值为0.

  把各个节点的sg值异或起来就是整个局面的sg值了(节点间互不影响)。修改操作的时候,就把总的sg值和 修改的节点原来的sg值 异或一下,在异或下新的sg值。

  总的sg值为0的话先手必败。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=10233;
 6 struct zs{
 7     int too,pre;
 8 }e[23333];
 9 int last[maxn],dep[maxn],tot;
10 int num[maxn];
11 int i,j,k,n,m,t,r,ans,a,b;
12 inline void insert(int a,int b){
13     e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;
14 }
15 void dfs(int x,int depth){
16     dep[x]=depth;
17     for(int i=last[x];i;i=e[i].pre)dfs(e[i].too,depth^1);
18 }
19 int ra,fh;char rx;
20 inline int read(){
21     rx=getchar();ra=0;fh=1;
22     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
23     if(rx=='-')rx=getchar(),fh=-1;
24     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
25 }
26 inline int getsg(int x){
27     if(dep[x])return num[x]%(r+1);
28     else return 0;
29 }
30 int main(){
31     n=read();t=read();r=read();
32     for(i=2;i<=n;i++)
33         a=read(),num[i]=read(),insert(a,i);
34     dfs(1,0);
35     t--;
36     a=read();b=read();num[a]=b;
37     for(i=2;i<=n;i++)ans^=getsg(i);
38     printf("%s\n",ans?"Yes":"No");
39     while(t--){
40         a=read();b=read();
41         ans^=getsg(a);
42         num[a]=b;
43         ans^=getsg(a);
44         printf("%s\n",ans?"Yes":"No");
45     }
46     return 0;
47 }
View Code

 

bzoj 1733: [Usaco2005 feb]Secret Milking Machine 神秘的挤奶机

  二分答案为mid,s连1,n连t,把长度不超过mid的边加进新图中,容量为1,看新图中最大流是否>=T。

  二分前可以先按边的长度离散化一下。。。反正最后的答案一定等于某条边的长度

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=201;
 7 struct zs{
 8     int too,pre;
 9     bool flow;
10 }e[160033];
11 int last[maxn],dis[maxn],cur[maxn],x[40023],y[40023],dist[40023],tmp[40023];
12 int dl[maxn];
13 int i,j,k,n,m,s,t,a,b,c,tot,T,mx,l,r,mid,ans;
14 int ra;char rx;
15 inline int read(){
16     rx=getchar();ra=0;
17     while(rx<'0'||rx>'9')rx=getchar();
18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
19 }
20 inline void insert(int a,int b){
21     e[++tot].too=b;e[tot].flow=1;e[tot].pre=last[a];last[a]=tot;
22     e[++tot].too=a;e[tot].flow=0;e[tot].pre=last[b];last[b]=tot;
23 }
24 inline bool bfs(){
25     memset(dis,255,(t+1)<<2);
26     int to,l=0,r=1,i,now;dl[1]=s;dis[s]=0;
27     while(l<r){
28         now=dl[++l];
29         for(i=last[now],to=e[i].too;i;i=e[i].pre,to=e[i].too)if(e[i].flow&&dis[to]==-1)
30             dis[to]=dis[now]+1,dl[++r]=to;
31     }
32     return dis[t]!=-1;
33 }
34 int dfs(int x,int mx){
35     if(x==t)return mx;
36     int used=0,w;register int i,to;
37     for(i=cur[x],to=e[i].too;i;cur[x]=i,i=e[i].pre,to=e[i].too)if(e[i].flow&&dis[to]==dis[x]+1){
38         w=dfs(to,1);if(w){
39             e[i].flow=0;e[i^1].flow=1;
40             used++;if(used==mx)return mx;
41         }
42     }
43     dis[x]=-1;return used;
44 }
45 int main(){
46     n=read();m=read();T=read();s=1;t=n;
47     for(i=1;i<=m;i++)x[i]=read(),y[i]=read(),dist[i]=tmp[i]=read();
48     sort(tmp+1,tmp+1+m);
49     l=0;r=m;
50     while(l<r){
51         mid=(l+r)>>1;
52         tot=1;memset(last,0,(t+1)<<2);
53         for(i=1;i<=m;i++)if(dist[i]<=tmp[mid])insert(x[i],y[i]),insert(y[i],x[i]);
54         ans=0;
55         while(bfs()&&ans<T)memcpy(cur,last,(t+1)<<2),ans+=dfs(s,2002333);
56         if(ans>=T)r=mid;else l=mid+1;
57     }
58     printf("%d\n",tmp[l]);
59     return 0;
60 }
View Code

 

bzoj 1740: [Usaco2005 mar]Yogurt factory 奶酪工厂

  傻逼题。。没错我是连傻逼题都不会写的傻逼。

  记录一下到当前,单位奶酪的最小代价就好了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #define ll long long
 5 using namespace std;
 6 int S,n;
 7 int ra;char rx;
 8 inline ll read(){
 9     rx=getchar();ra=0;
10     while(rx<'0'||rx>'9')rx=getchar();
11     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
12 }
13 int main(){
14     n=read();S=read();
15     register int now,i,low=100233333;register ll ans=0;
16     for(i=n;i;low+=S,i--){
17         now=read();if(now<low)low=now;
18         ans+=read()*low;
19     }
20     printf("%lld\n",ans);
21     return 0;
22 }
View Code

 

bzoj 1742: [Usaco2005 nov]Grazing on the Run 边跑边吃草

  区间dp(因为走到哪里吃到哪里。。吃了的范围肯定是一段区间)。中英文数据范围不一致= =其实数据范围只有n<=1000.。。

  f[i][j][0]表示吃完[i,j]这段区间里的草后站在左端点(i点)的最少腐败值。f[i][1]表示吃完[i,j]后站在右端点的最少腐败值。dis(i,j)表示点i与点j间的距离

  初始化f[i][i][0]=f[i][i][1]=dis(i,p)*n。

  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) ) }...f[i][j][1]类似,就是从f[i][j-1][0..1]转移过来。。

  行走距离乘上(n-(j-i))是因为走这段路时,会使还没吃的(n-(j-i))棵草的腐败值都加上所花的时间。

  如果用f[i][j][0..1]表示吃了的区间长度为i,区间以j结尾,吃完站在左右端点的最小腐败值,就可以省掉一维= =

  压了下常数然后#1了。。。。然而代码更丑了TAT。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 using namespace std;
 7 const int maxn=3001;
 8 int f[maxn][2];
 9 int len,s,mxj,n;
10 int a[maxn],b[maxn];
11 int ra;char rx;
12 inline int read(){
13     rx=getchar();ra=0;
14     while(rx<'0'||rx>'9')rx=getchar();
15     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
16 }
17 int main(){
18     int i,j,mxj,tmp;
19     n=read();s=read();
20     for(i=1;i<=n;i++)a[i]=read();sort(a+1,a+1+n);
21     for(i=1;i<=n;b[i]=a[i+1]-a[i],i++)f[i][0]=f[i][1]=abs(s-a[i])*n;
22     for(i=1,mxj=n-1;i<n;mxj--,i++)for(j=1;j<=mxj;j++)
23     tmp=f[j][0],f[j][0]=min(f[j+1][0]+mxj*b[j],f[j+1][1]+mxj*(a[j+i]-a[j])),
24                 f[j][1]=min(tmp+mxj*(a[j+i]-a[j]),f[j][1]+mxj*b[j+i-1]);
25     printf("%d\n",min(f[1][0],f[1][1]));
26     return 0;
27 }
View Code

 

bzoj 3126: [Usaco2013 Open]Photo

  dp....先把区间按右端点排序。。设题目给出的区间为l[],r[]

  f[i]表示点1~第i个区间的右端点 中可能的点的最大数目。。

  f[i]=max{ f[j]+1 },(不存在任意一段区间满足j<L[k],R[k]<i,也不存在任意一段区间满足L[k]<=j,R[k]>=i)。。。。

  所以可以预处理一下。。。不清楚如何用单调队列写TAT。。只好写个线段树了。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 const int maxn=200233;
 8 struct zs{
 9     int l,r;
10 }a[maxn],b[maxn];
11 int minl[maxn],maxl[maxn],mp[maxn],f[maxn];
12 int mx[maxn<<2];
13 int i,j,n,m,tmpl,top,tmp,ans,size;
14 bool can[maxn];
15 struct poi{
16     int pos,val;
17 };
18 priority_queue<poi>q;
19 bool operator <(poi a,poi b){return a.val<b.val;}
20 bool cmp1(zs a,zs b){return a.r<b.r;}
21 bool cmp2(zs a,zs b){return a.r>b.r;}
22 int ra;char rx;
23 inline int read(){
24     rx=getchar();ra=0;
25     while(rx<'0'||rx>'9')rx=getchar();
26     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
27 }
28 inline void update(int x,int val){
29     for(x+=size;x&&mx[x]<val;x>>=1)mx[x]=val;
30 }
31 inline int getmax(int l,int r){
32 //  printf("       %d--%d:",l,r);
33     l+=size;r+=size;int ans=max(mx[l],mx[r]);
34     if(l<=size){
35         if(r>=size)ans=max(ans,0);
36         l=size+1;
37     }
38     if(l>=r)return ans;
39     ans=max(ans,mx[l]);
40 //  printf("                    %d--%d:",l-size,r-size);
41     while((l^1)!=r){
42         if((!(l&1))&&mx[l^1]>ans)ans=mx[l^1];
43         if((r&1)&&mx[r^1]>ans)ans=mx[r^1];
44         l>>=1;r>>=1;
45     }
46 //  printf("%d\n",ans);
47     return ans;
48 }
49 int main(){
50     m=read();n=read();
51     for(i=1;i<=n;i++)a[i].l=read(),a[i].r=read(),mp[a[i].l]++,mp[a[i].r+1]--;
52     for(i=1,tmp=0;i<=m;i++)tmp+=mp[i],can[i]=(tmp>0);
53     memcpy(b,a,(n+1)<<3);
54     sort(b+1,b+1+n,cmp1);top=n;tmpl=m+1;
55     for(i=m;i;i--){
56         while(top&&b[top].r>=i)tmpl=min(tmpl,b[top--].l);
57         minl[i]=min(i,tmpl);
58         if(!can[i])minl[i]=m+1;
59     }tmpl=-1;
60     for(i=top=1;i<=m;i++){
61         while(top<=n&&b[top].r<i)tmpl=max(tmpl,b[top++].l);
62         maxl[i]=tmpl-1;
63         if(!can[i])maxl[i]=-1;
64     }
65 //  for(i=1;i<=m;i++)printf("      %d %d\n",maxl[i]+1,minl[i]-1);
66     memset(f,180,(m+1)<<2);f[0]=0;
67     for(size=1;size<m;size<<=1);size--;
68     memset(mx,180,(size*2+2)<<2);
69     for(i=1;i<=m;i++){
70         if(maxl[i]+1<minl[i])f[i]=getmax(maxl[i]+1,minl[i]-1)+1,update(i,f[i]);//,printf("  %d %d\n",i,f[i]);
71         ans=max(ans,f[i]);
72  //       printf("  %d %d\n",i,f[i]);
73     }
74     for(i=1;i<=n;i++)if(getmax(b[i].l,b[i].r)<=0){puts("-1");return 0;}
75     printf("%d\n",ans);
76     return 0;
77 }
View Code

 

bzoj 1722: [Usaco2006 Mar] Milk Team Select 产奶比赛

  树形dp。。f[i][j][0]表示在以i为根的子树中(不取i),有j对血缘关系,产出牛奶的最大值。f[i][j][1]同理,但要取i。。

  求f[i][j][0]的时候,就是对各个孩子跑一遍01背包= =

  f[i][j][1]类似,但是注意血缘关系= =。。。。太蛋疼具体就不写了TAT

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=505;
 6 struct zs{
 7     int too,pre;
 8 }e[23333];
 9 int last[maxn],tot;
10 int f[maxn][maxn][3];//f[i][j][2]=max(f[i][j][0],f[i][j][1])...
11 int pre[maxn],size[maxn];
12 int val[maxn];
13 int i,j,k,n,m,x,a,sum;
14 int ra,fh;char rx;
15 inline int read(){
16     rx=getchar();ra=0;fh=1;
17     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
18     if(rx=='-')rx=getchar(),fh=-1;
19     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
20 }
21 inline void insert(int a,int b){
22     e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;
23 }
24 void dfs(int x){
25     int i,j,to,k,mx,k1;size[x]=1;
26     memset(f[x],233,sizeof(f[x]));
27     f[x][0][0]=0;f[x][0][1]=val[x];f[x][0][2]=max(0,val[x]);
28     for(i=last[x];i;i=e[i].pre)dfs(e[i].too),size[x]+=size[e[i].too];
29     if(size[x]==1)return;
30    if(x!=0)
31     for(i=last[x],to=e[i].too;i;i=e[i].pre,to=e[i].too){
32         mx=size[to];while(mx&&f[to][mx][2]<=-100233333)mx--;
33         for(j=0;j<size[x];j++)pre[j]=f[x][j][1];
34         for(j=size[x]-1;j>=0;j--){
35             for(k=0;k<=mx;k++)f[x][j][0]=max(f[x][j][0],f[x][j-k][0]+f[to][k][2]);
36             if(pre[0]+f[to][j][0]>f[x][j][1])f[x][j][1]=pre[0]+f[to][j][0];
37              
38             if(mx>=j)mx=j-1;
39             for(k=0,k1=j-k;k<=mx&&k<j;k++,k1--){
40                 if(pre[k1]+f[to][k][0]>f[x][j][1])f[x][j][1]=pre[k1]+f[to][k][0];
41                 if(pre[k1-1]+f[to][k][1]>f[x][j][1])f[x][j][1]=pre[k1-1]+f[to][k][1];
42             }
43         }
44     }else
45         for(i=last[x],to=e[i].too;i;i=e[i].pre,to=e[i].too)
46         for(j=n-1;j>=0;j--)for(k=0;k<=j;k++)f[x][j][0]=max(f[x][j][0],f[x][j-k][0]+f[to][k][2]);
47     for(i=0;i<n;i++)f[x][i][2]=f[x][i][0]>f[x][i][1]?f[x][i][0]:f[x][i][1];
48 }
49 int main(){
50     n=read();x=read();
51     for(i=1;i<=n;i++){
52         val[i]=read(),a=read(),insert(a,i);
53         if(val[i]>=0)sum+=val[i];
54     }
55     if(sum<x){puts("-1");return 0;}
56     dfs(0);
57     for(i=n-1;f[0][i][0]<x;i--);
58     printf("%d\n",i);
59     return 0;
60 }
View Code

 

bzoj 1779: [Usaco2010 Hol]Cowwar 奶牛战争

  比较简单的最大流。。。四分图233。。每个点拆成四个点。。假设图画起来是四列,每列n个点的。。

  1、第一列中John的奶牛与S相连;

  2、第一列John的每头奶牛与第二列中的可达位置(原地或相邻,且没有Tom的牛)相连;

  3、第二列中的每个可达位置与第三列中的自己连一条边。(一个点上只能站一只牛)

  4、第三列每个位置与它第四列中相邻的(能攻击到的)、有Tom的牛的位置相连。最后第四列的Tom的牛连一条到T的边。。。

  各边容量都为1。。。求出来的最大流就是答案。。。可以把图中一些没用的点去掉= =

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=4023;
 6 struct zs{
 7     int too,pre;
 8     bool flow;
 9 }e[32333];
10 struct edge{
11     int too,pre;
12 }E[10233];
13 int last[maxn],tot=1,LAST[1002],TOT,ans;
14 int jim[1002],tom[1002],id[1002],cow[1002];
15 short dis[maxn];
16 int dl[maxn];
17  
18 int s,t,i,j,a,b,n,m,to;
19 bool istom[1002];
20 int ra;char rx;
21 inline int read(){
22     rx=getchar();ra=0;
23     while(rx<'0'||rx>'9')rx=getchar();
24     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
25 }
26 inline void insert(int a,int b){
27 //  printf("    %d-->%d\n",a,b);
28     e[++tot].too=b;e[tot].flow=1;e[tot].pre=last[a];last[a]=tot;
29     e[++tot].too=a;e[tot].flow=0;e[tot].pre=last[b];last[b]=tot;
30 }
31 inline void insmap(int a,int b){
32     E[++TOT].too=b;E[TOT].pre=LAST[a];LAST[a]=TOT;
33     E[++TOT].too=a;E[TOT].pre=LAST[b];LAST[b]=TOT;
34 }
35 inline bool bfs(){
36     int l=0,r=1,i,now;
37     memset(dis,255,(t+1)<<1);
38     dl[1]=s;dis[s]=0;
39     while(l<r)
40         for(now=dl[++l],i=last[now];i;i=e[i].pre)
41             if(e[i].flow&&dis[e[i].too]==-1)
42             dl[++r]=e[i].too,dis[e[i].too]=dis[now]+1;
43     return dis[t]!=-1;
44 }
45 int dfs(int x,int mx){
46     if(x==t)return mx;
47     int used=0,i,to,w;dis[x]++;
48     for(i=last[x],to=e[i].too;i;i=e[i].pre,to=e[i].too)if(e[i].flow&&dis[to]==dis[x]){
49         w=dfs(to,1);if(w){
50             e[i].flow=0;e[i^1].flow=1;
51             used++;if(used==mx){dis[x]--;return mx;}
52         }
53     }
54     dis[x]=-1;return used;
55 }
56 int main(){
57     n=read();m=read();s=0;int numj=0,numt=0;
58     for(i=1;i<=n;i++){
59         for(rx=getchar();rx!='T'&&rx!='E'&&rx!='J';rx=getchar());
60         if(rx=='J')insert(s,++numj),jim[i]=numj,cow[numj]=i;
61         else if(rx=='T')tom[i]=++numt,istom[i]=1;
62     }int tmp=0;
63     for(i=1;i<=n;i++)if(!istom[i])id[i]=++tmp;
64     t=numj+(n-numt)*2+numt+1;
65     for(i=1;i<=m;i++)a=read(),b=read(),insmap(a,b);
66     for(i=last[0];i;i=e[i].pre){
67         to=cow[e[i].too];insert(jim[to],numj+id[to]);
68         for(j=LAST[to];j;j=E[j].pre)if(!istom[E[j].too])
69             insert(jim[to],numj+id[E[j].too]);
70     }
71     for(i=1;i<=n;i++)if(!istom[i]){
72         insert(numj+id[i],numj+id[i]+(n-numt));
73         for(j=LAST[i];j;j=E[j].pre)if(istom[E[j].too])
74             insert(numj+id[i]+(n-numt),numj+(n-numt)*2+tom[E[j].too]);
75     }else insert(numj+(n-numt)*2+tom[i],t);
76     while(bfs())ans+=dfs(s,100002333);
77     printf("%d\n",ans);
78     return 0;
79 }
View Code

 

bzoj 1739: [Usaco2005 mar]Space Elevator 太空电梯

  背包dp。。因为最大高度才4w。。。所以直接用f[i]表示能否堆到i这个高度。

  把方块按最大高度升序排序,按顺序对每种方块i跑多重背包。。。似乎也可以sxbk把f数组换成bitset。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=502;
 7 struct zs{
 8     int mx,c,h;
 9 }a[maxn];
10 bool f[40233];
11 int i,j,n,m,ans,k,nowc,nowh,nowmx;
12 int ra,fh;char rx;
13 inline int read(){
14     rx=getchar();ra=0;fh=1;
15     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
16     if(rx=='-')rx=getchar(),fh=-1;
17     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
18 }
19 bool cmp(zs a,zs b){return a.mx<b.mx;}
20 int main(){
21     n=read();f[0]=1;
22     for(i=1;i<=n;i++)a[i].h=read(),a[i].mx=read(),a[i].c=read(),ans=max(ans,a[i].mx);
23     sort(a+1,a+1+n,cmp);
24     for(i=1;i<=n;i++){nowc=a[i].c;nowh=a[i].h;nowmx=a[i].mx;
25         for(j=1;j<=nowc;j++)
26         for(k=nowmx;k>=nowh;k--)f[k]|=f[k-nowh];
27     }
28     while(!f[ans]&&ans)ans--;
29     printf("%d\n",ans);
30     return 0;
31 }
View Code

 

bzoj 2272: [Usaco2011 Feb]Cowlphabet 奶牛文字

  dp。。。f[i][j][k]表示长度为(i+j)的单词中,有i个大写字母,j个小写字母,最后一个字母为k的方案数。

  f[i][j][k]=sum{ f[i-1][j][k1] },(存在词素(k1,k),k为大写字母时)

  或f[i][j][k]=sum{ f[i][j-1][k1] },(存在词素(k1,k),k为小写字母时)

  大概是题目太水没人压常数嗯。。一开始卡常太sxbk连样例都过不了。。实在不敢调就重新写了个正常点的。。

  取余的时候用减法,先把词素的俩字母连边就可以#1了= =

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=253;
 7 const int modd=97654321;
 8 int f[maxn][maxn][53];
 9 int mp[53][53],map[53],num[53];
10 bool used[53];
11 char x1,x2;int tmp1,tmp2,tot,upnum,lownum,tmp,to,ans;
12 int i,j,k,n,m,l,p,u;
13 bool up,low;
14 int main(){
15     scanf("%d%d%d",&u,&l,&p);
16     for(i=1;i<=p;i++){
17         for(x1=getchar();!isupper(x1)&&!islower(x1);x1=getchar());
18         for(x2=getchar();!isupper(x2)&&!islower(x2);x2=getchar());
19         if(x1>='a')tmp1=x1-'a'+26;else tmp1=x1-'A';
20         if(x2>='a')tmp2=x2-'a'+26;else tmp2=x2-'A';
21         if(!used[tmp1])map[++map[0]]=tmp1,used[tmp1]=1;
22         if(!used[tmp2])map[++map[0]]=tmp2,used[tmp2]=1;
23         mp[tmp1][++num[tmp1]]=tmp2;
24     }
25     sort(map+1,map+1+map[0]);for(i=1;i<=map[0];i++)if(map[i]>=26)break;upnum=i-1;
26     for(i=1;i<=upnum;i++)f[1][0][map[i]]=1;for(i=upnum+1;i<=map[0];i++)f[0][1][map[i]]=1;
27 //  for(i=1;i<=upnum;i++)printf("%d  ",map[i]);printf("\n");
28 //  for(i=upnum+1;i<=map[0];i++)printf("%d  ",map[i]);printf("\n");
29     for(i=0;i<=u;i++)for(j=0;j<=l;j++)if(i+j>=2){
30         up=i>0;low=j>0;
31         if(up)for(tmp=1,k=map[1];tmp<=upnum;f[i][j][k]=ans,ans=0,k=map[++tmp])
32                 for(tmp1=1,to=mp[k][tmp1];tmp1<=num[k];to=mp[k][++tmp1])
33                     ans+=f[i-1][j][to],ans-=ans>=modd?modd:0;
34         if(low)for(tmp=upnum+1,k=map[tmp];tmp<=map[0];f[i][j][k]=ans,ans=0,k=map[++tmp])
35                 for(tmp1=1,to=mp[k][tmp1];tmp1<=num[k];to=mp[k][++tmp1])
36                     ans+=f[i][j-1][to],ans-=ans>=modd?modd:0;
37     }
38     for(i=0;i<52;i++)ans+=f[u][l][i],ans-=ans>=modd?modd:0;
39     printf("%d\n",ans);
40     return 0;
41 }
View Code

 

bzoj 1752: [Usaco2005 qua]Til the Cows Come Home

  为何一道最短路的AC人数和AC率这么低= =

  为何我spfa调优先队列和普通版的一样慢TAT

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 #include<algorithm>
 6 using namespace std;
 7 const int maxn=1001;
 8 struct zs{
 9     int too,pre,dis;
10 }e[4001];
11 struct poi{
12     int pos,dis;
13 };
14 int i,j,n,m,a,b,tot,c,size;
15 int last[maxn],dis[maxn];
16 bool used[maxn];
17 priority_queue<poi>q;
18 inline void insert(int a,int b,int c){
19     e[++tot].too=b;e[tot].dis=c;e[tot].pre=last[a];last[a]=tot;
20     e[++tot].too=a;e[tot].dis=c;e[tot].pre=last[b];last[b]=tot;
21 }
22 bool operator <(poi a,poi b){return a.dis>b.dis;}
23 int ra;char rx;
24 inline int read(){
25     rx=getchar();ra=0;
26     while(rx<'0'||rx>'9')rx=getchar();
27     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
28 }
29 int main(){
30     m=read();n=read();memset(dis,60,(n+1)<<2);
31     for(i=1;i<=m;i++)a=read(),b=read(),c=read(),insert(a,b,c);
32     dis[n]=0;size=1;q.push((poi){n,0});int pos,dist,to;
33     while(size&&!used[1]){
34         while(size&&used[q.top().pos])q.pop(),size--;
35         pos=q.top().pos;dist=q.top().dis;used[pos]=1;if(pos==1)break;
36         for(i=last[pos],to=e[i].too;i;i=e[i].pre,to=e[i].too)if(dis[to]>dist+e[i].dis)
37             dis[to]=dist+e[i].dis,q.push((poi){to,dis[to]}),size++;
38     }
39     printf("%d\n",dis[1]);
40     return 0;
41 }
View Code

 

bzoj 1738: [Usaco2005 mar]Ombrophobic Bovines 发抖的牛

  一开始看成总时间最小以为是费用流。。。结果发现是二分答案+最大流判定

  先用floyd把两两之间的最短路求出来,然后二分答案为mid,

  建个二分图,S连每个点x,容量为开始前牛的数量,x'连T,容量为雨棚容量。两个点间的最短路径长如果<=mid的话就在新图中加条边,容量无穷。

  检验新图中最大流是否为牛的总数。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=404;
 7 struct zs{
 8     int too,pre,flow;
 9 }e[82333];
10 int last[maxn],dis[maxn],dl[maxn],num[maxn],mx[maxn];
11 ll map[202][202];
12 int i,j,k,n,m,a,b,c,s,t,sumnum,summx,tot;
13 ll l,r,mid;
14 int ra;char rx;
15 inline int read(){
16     rx=getchar();ra=0;
17     while(rx<'0'||rx>'9')rx=getchar();
18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
19 }
20 inline bool bfs(){
21     int l=0,r=1,i,now;
22     memset(dis,255,(t+1)<<2);dl[1]=s;dis[s]=0;
23     while(l<r){
24         now=dl[++l];
25         for(i=last[now];i;i=e[i].pre)if(e[i].flow&&dis[e[i].too]==-1)
26         dl[++r]=e[i].too,dis[e[i].too]=dis[now]+1;
27     }
28     return dis[t]!=-1;
29 }
30 int dfs(int x,int mx){
31     if(x==t)return mx;
32     int i,used=0,w,to;
33     for(i=last[x],to=e[i].too;i;i=e[i].pre,to=e[i].too)if(e[i].flow&&dis[to]==dis[x]+1){
34         w=dfs(to,min(mx-used,e[i].flow));if(w){
35             e[i].flow-=w;e[i^1].flow+=w;
36             used+=w;if(used==mx)return mx;
37         }
38     }
39     dis[x]=-1;return used;
40 }
41 inline void insert(int a,int b,int c){
42 //  printf("%d-->%d:%d\n",a,b,c);
43     e[++tot].too=b;e[tot].flow=c;e[tot].pre=last[a];last[a]=tot;
44     e[++tot].too=a;e[tot].flow=0;e[tot].pre=last[b];last[b]=tot;
45 }
46 inline bool can(ll x){
47     int i,j;//printf("!  %lld\n",x);
48     for(i=1;i<=n;i++)insert(s,i,num[i]),insert(i+n,t,mx[i]);
49     for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(map[i][j]<=x)insert(i,j+n,1002333333);
50     int ans=0;
51     while(bfs())ans+=dfs(s,100002333);
52     return ans==sumnum;
53 }
54 int main(){
55     n=read();m=read();
56     for(i=0;i<=n;i++)memset(map[i],60,(n+1)<<3);
57     for(i=1;i<=n;i++)num[i]=read(),mx[i]=read(),map[i][i]=0,summx+=mx[i],sumnum+=num[i];
58     if(summx<sumnum){puts("-1");return 0;}
59     for(i=1;i<=m;i++){
60         a=read();b=read();c=read();
61         if(c<map[a][b])map[a][b]=map[b][a]=c;
62     }
63     for(k=1;k<=n;k++)for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(map[i][k]+map[k][j]<map[i][j])map[i][j]=map[i][k]+map[k][j];
64  
65     for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(map[i][j]<map[0][0]&&map[i][j]>r)r=map[i][j];ll mxl=r;
66     l=0;r++;s=0;t=n+n+1;tot=1;
67     while(l<r){
68         mid=(l+r)>>1;
69         if(can(mid))r=mid;else l=mid+1;
70         if(l<r)memset(last,0,(t+1)<<2),tot=1;
71     }
72     printf("%lld\n",l<=mxl?l:-1);
73     return 0;
74 }
View Code

 

bzoj 1986: [USACO2004 Dec] Dividing the Path 划区灌溉

  dp+单调队列优化。。f[i]表示灌溉了1~i(全体右移一位从1开始。。)的最小喷灌器总数。设各草区左右端点为l[],r[]

  f[i]=min{ f[j] }+1,(1、i和j为偶数,2*A<=i-j<=2*B;2、不存在k,使l[k]<=j,r[k]>j)

  第二个转移条件也就是i和j都不存在于任意[ l[i],r[i]-1 ]中。

  调个优先队列就行了。。每次算f[i]前把f[i-A*2]入队。时间复杂度O(n)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 const int maxn=1000033;
 6 int dl[maxn],f[maxn];
 7 int map[maxn];
 8 int i,j,n,m,len,a,b,l,r,A,B,now;
 9 int ra;char rx;
10 inline int read(){
11     rx=getchar();ra=0;
12     while(rx<'0'||rx>'9')rx=getchar();
13     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
14 }
15 int main(){
16     n=read();len=read();A=read();B=read();
17     memset(f,60,(min(len,A*2)+1)<<2);
18     for(i=1;i<=n;i++)
19         a=read(),b=read(),map[min(a+1,b)]++,map[b]--;
20     int inf=600233333;
21     l=1;r=0;
22     f[0]=0;
23     a=A*2-B*2;b=0;for(i=1;i<A*2;i++)now+=map[i];
24     for(i=A<<1;i<=len;i+=2,a+=2,b+=2){
25         while(l<=r&&f[dl[r]]>=f[b])r--;dl[++r]=b;if(f[dl[r]]>=inf)r--;
26         now+=map[i]+map[i-1];if(now){f[i]=inf;continue;}
27         while(l<=r&&dl[l]<a)l++;
28         f[i]=(l<=r&&f[dl[l]]<inf)?(f[dl[l]]+1):inf;
29     }
30     printf("%d\n",f[len]<inf?f[len]:-1);
31     return 0;
32 }
View Code

 

bzoj 1605: [Usaco2008 Open]Crisis on the Farm 牧场危机

  DP。。先预处理出val[i][j],表示使各牛群横纵坐标分别增加了i和j后能救几头牛(只算最后一次吹哨救的)。。

  f[i][j][k]表示吹了k次哨子,使各牛群横纵坐标分别增加了i和j能救的最多奶牛数。

  f[i][j][k]=max{ f[i1][j1][k-1] }+val[i][j]。(点(i1,j1)与点(i,j)相邻)。

  觉得直接dp的话冗余状态略蛋疼就借(chao)鉴(xi)题解代码写了记忆化搜索= =输出方案的话记录下f[i][j][k]是从哪里转移来的

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 using namespace std;
 6 const int maxn=61;
 7 const int maxstep=31;
 8 const int xx[5]={0,1,0,0,-1},yy[5]={0,0,1,-1,0};
 9 int next[maxn][maxn][maxstep],f[maxn][maxn][maxstep],val[maxn][maxn];
10 int x[1001],y[1001],gx[1001],gy[1001];
11 int i,j,k,n,m,a,b,deltax,deltay;
12 char map[5]={0,'E','N','S','W'};
13 int ra;char rx;
14 inline int read(){
15     rx=getchar();ra=0;
16     while(rx<'0'||rx>'9')rx=getchar();
17     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
18 }
19 //f[i][j][k]表示横纵坐标增加了i和j,剩k次吹哨机会时的最大值。
20 int dfs(int dx,int dy,int rest){
21     if(rest<=0)return val[dx][dy];
22     if(next[dx][dy][rest])return f[dx][dy][rest];
23     next[dx][dy][rest]=1;f[dx][dy][rest]=dfs(dx+xx[1],dy+yy[1],rest-1);
24     for(int i=2;i<=4;i++)
25     if(dfs(dx+xx[i],dy+yy[i],rest-1)>f[dx][dy][rest])
26         f[dx][dy][rest]=dfs(dx+xx[i],dy+yy[i],rest-1),next[dx][dy][rest]=i;
27     f[dx][dy][rest]+=val[dx][dy];//printf("%d %d %d   %d     %d\n",dx,dy,rest,f[dx][dy][rest],next[dx][dy][rest]);
28     return f[dx][dy][rest];
29 }
30 int main(){
31     n=read();m=read();k=read();
32     for(i=1;i<=n;i++)x[i]=read(),y[i]=read();
33     for(i=1;i<=m;i++){
34         a=read();b=read();
35         for(j=1,deltax=abs(x[j]-a),deltay=abs(y[j]-b);j<=n;deltax=abs(x[++j]-a),deltay=abs(y[j]-b))
36             if(deltax+deltay<=k)val[a-x[j]+30][b-y[j]+30]++;
37     }
38     printf("%d\n",dfs(30,30,k)-val[30][30]);
39     int nowx=30,nowy=30;
40     for(;k;k--){
41         putchar(map[next[nowx][nowy][k]]);
42         if(next[nowx][nowy][k]<2||next[nowx][nowy][k]>3)nowx+=xx[next[nowx][nowy][k]];else nowy+=yy[next[nowx][nowy][k]];
43     }
44     putchar('\n');
45     return 0;
46 }
View Code

 

posted @ 2015-12-24 20:15  czllgzmzl  阅读(548)  评论(0编辑  收藏  举报