zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",now,j,f[now][j]);
    43     }
    44     printf("%lld
    ",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
    ",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
    ",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
    ",(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
    ",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
    ",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
    ",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
    ");else printf("%d
    ",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("
    ");
    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
    ",(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
    ",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
    ",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
    ",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("
    ");
    63 //  for(i=1;i<=m;i++)printf("%lld    ",pre1[i]);printf("
    ");
    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
    ",sa[i]);
    68 //  for(i=1;i<=n;i++)printf("  %d
    ",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("
    ");
    76         if(samelen<m-pos+1&&L<n)samelen=max(samelen,get1(sa[L+1],pos));
    77         ans++;pos+=samelen;//printf("          %d
    ",pos);
    78     }
    79     printf("%d
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",i,f[i]);
    71         ans=max(ans,f[i]);
    72  //       printf("  %d %d
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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("
    ");
    28 //  for(i=upnum+1;i<=map[0];i++)printf("%d  ",map[i]);printf("
    ");
    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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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('
    ');
    45     return 0;
    46 }
    View Code
  • 相关阅读:
    软件开发的升级打怪攻略:从新手到高级工程师
    Java实现递归将嵌套Map里的字段名由驼峰转为下划线
    生活是什么
    批量下载网站图片的Python实用小工具
    工作的方法
    工作的心境
    LODOP直接导出图片不弹框
    LODOP打印table超宽用省略号带'-'的内容换行问题
    LODOP打印table表格宽度固定-超宽隐藏
    如何领购和作废电子发票流程
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5074166.html
Copyright © 2011-2022 走看看