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
  • 相关阅读:
    开源项目
    [Accessibility] Missing contentDescription attribute on image [可取行]失踪contentDescription属性图像
    Android 布局 中实现适应屏幕大小及组件滚动
    EF 错误记录
    EasyUI 加载时需要显示和隐藏 panel(面板)内容破版问题
    IE 报表缩放后页面破版
    VS 2017 引入nuget 问题
    SSRS 报表显示页面 asp net session丢失或者找不到 asp net session has expired or could not be found()
    log4net 配置
    网站
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5074166.html
Copyright © 2011-2022 走看看