bzoj usaco 金组水题题解(1)

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

——————————————————————————————————————————————————————————————————————————————

  写(被虐)了整整一个月b站上usaco的金组题。。。然而到现在总共只写了100道上下TAT(当然是按AC人数降序排列的了)(另外,是用云神的号写的= =毕竟三百大洋)

  大概不到1\3是自己写的,一半是有大概方向后跑去看题解,剩下的就是毫无思路就去看题解作死的了= =

  感觉金组题还是比较适合自己当前水平的QAQ。。。所以大致的写下题解加深下印象吧。。。对于比较经典而自己又不熟的题打算专门另写题解(瞬间就挖了一个大坑)

这里贴出50道。。。

 

bzoj 1597:[Usaco2008 Mar]土地购买    

  斜率优化入门题。f[i]表示买前i块土地的最小费用

  f[i]=min{
      f[j]+max_w(j+1,i)*max_l(j+1,i),( 0<=j<i )
  }// max_w(j+1,i)和max_l(j+1,i)分别表示第j+1块土地到第i块土地中宽度和长度的最大值

  首先去掉那些被别的土地完全覆盖的土地(因为不会对答案有任何影响),剩下的按宽度排序。宽度升序排序的话,长度一定是降序的(被完全覆盖的都被去掉了)

  方程就变成  f[i]=min{  f[j]+wid[i]*len[j+1]  },(0<=j<i)

  剩下的就是斜率优化了。。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define d double
 6 #define ll long long
 7 using namespace std;
 8 const int maxn=50023;
 9 struct zs{
10     int x,y;
11 }a[maxn];
12 bool cant[maxn];
13 ll f[maxn];
14 int l,r,dl[maxn];
15 int i,j,k,n,m;
16 char rx;int ra;
17  
18  
19 bool cmp(zs a,zs b){return a.x<b.x||(a.x==b.x&&a.y>b.y);
20 }
21 bool smaller(int aa,int b,int c){
22     return  (ll)(f[c]-f[b])*(ll)(a[aa+1].y-a[b+1].y) <= (ll)(f[b]-f[aa])*(ll)(a[b+1].y-a[c+1].y);
23     /*return (d)(f[i]-f[dlr])/(d)(a[dlr+1].y-a[i+1].y)
24             <
25            (d)(f[dlr]-f[pre])/(d)(a[pre+1].y-a[dlr+1].y);*/
26 }
27 inline int read(){
28     rx=getchar();ra=0;
29     while(rx<'0'||rx>'9')rx=getchar();
30     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
31 }
32 int main(){
33     n=read();
34     for(i=1;i<=n;i++)a[i].x=read(),a[i].y=read();
35     sort(a+1,a+1+n,cmp);int tmp=a[n].y;
36     for(i=n-1;i;i--)
37         if(a[i].y<=tmp)cant[i]=1;else tmp=a[i].y;  tmp=0;
38     for(i=1;i<=n;i++)if(!cant[i])a[++tmp].x=a[i].x,a[tmp].y=a[i].y;  n=tmp;
39     for(i=1;i<=n;i++){
40         while(l<r&&  (ll)(f[dl[l+1]]-f[dl[l]]) < (ll)a[i].x*(ll)(a[dl[l]+1].y-a[dl[l+1]+1].y)  )l++;
41         f[i]=f[dl[l]]+(ll)a[i].x*a[dl[l]+1].y;
42         while(l<r&& smaller(dl[r-1],dl[r],i))r--;dl[++r]=i;
43     }
44     printf("%lld\n",f[n]);
45     return 0;
46 }
View Code

 

 

bzoj 1699:[Usaco2007 Jan]Balanced Lineup排队

  rmq裸题。。。因为不涉及区间修改的操作所以可以用线段树的点树写法(建成一个堆)来写。。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 const int maxn=52333;
 6 int mx[maxn<<2],mn[maxn<<2],a[maxn];
 7 int i,j,k,n,m,len,L,R,ansmax,ansmin;
 8 char s[11];
 9 inline void outx(int x){//len=0;
10     while(x||!len)s[len++]=x%10,x/=10;
11     while(len)len--,putchar(s[len]+'0');putchar('\n');
12 }
13 inline void inx(int &x){
14     int ch;x=0;
15     for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
16     for(;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());;
17 }
18 int main(){
19     scanf("%d%d",&n,&m);int dep=0;
20     while(1<<dep<n)dep++;int stnum=(1<<dep)-1;dep++;
21     for(i=1;i<=n;i++)inx(a[i]),mx[stnum+i]=mn[stnum+i]=a[i];
22     for(i=stnum;i;i--){
23         if(mx[i<<1]>mx[(i<<1)|1])mx[i]=mx[i<<1];else mx[i]=mx[(i<<1)|1];
24         if(mn[i<<1]<mn[(i<<1)|1])mn[i]=mn[i<<1];else mn[i]=mn[(i<<1)|1];
25     }
26     for(i=1;i<=m;i++){
27         inx(L);inx(R);ansmax=max(a[L],a[R]);ansmin=min(a[L],a[R]);
28         L+=stnum;R+=stnum;if(L==R)outx(0);else{
29         for(;(L^R)!=1;L>>=1,R>>=1){
30             if(R&1){if(mx[R^1]>ansmax)ansmax=mx[R^1];if(mn[R^1]<ansmin)ansmin=mn[R^1];}
31             if(!(L&1)){if(mx[L^1]>ansmax)ansmax=mx[L^1];if(mn[L^1]<ansmin)ansmin=mn[L^1];}
32         };outx(ansmax-ansmin);}
33          
34     }
35     return 0;
36 }
View Code

 

 

bzoj 1230:[Usaco2008 Nov]lites 开关灯

  线段树区间修改。。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=132333;
 6 int num[2][maxn<<1],a[maxn<<1],b[maxn<<1],l[maxn<<1],r[maxn<<1],mid[maxn<<1];
 7 bool rev[maxn<<1];
 8 int i,j,k,n,m,L,R,id,tot;
 9  
10 char rx;int ra;
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 pushdown(int now,int l,int r){
17     rev[l]^=1;rev[r]^=1;
18     swap(num[0][l],num[1][l]);swap(num[0][r],num[1][r]);
19     rev[now]=0;
20 }
21 void change(int now,int a,int b){
22     if(L<=a&&R>=b){rev[now]^=1;swap(num[0][now],num[1][now]);return;}
23     if(rev[now])pushdown(now,l[now],r[now]);
24     if(L<=mid[now])change(l[now],a,mid[now]);
25     if(R>mid[now])change(r[now],mid[now]+1,b);
26     num[0][now]=num[0][l[now]]+num[0][r[now]];
27     num[1][now]=num[1][l[now]]+num[1][r[now]];
28 }
29 int query(int now,int a,int b){
30     if(L<=a&&R>=b)
31         return num[1][now];
32     if(rev[now])pushdown(now,l[now],r[now]);
33     if(R<=mid[now])return query(l[now],a,mid[now]);
34     else if(L>mid[now])return query(r[now],mid[now]+1,b);
35     else return query(l[now],a,mid[now])+query(r[now],mid[now]+1,b);
36 }
37 void build(int a,int b){
38     int now=++tot;
39     num[0][now]=b-a+1;mid[now]=(a+b)>>1;
40     if(a<b){
41         l[now]=tot+1;
42         build(a,mid[now]);r[now]=tot+1;
43         build(mid[now]+1,b);
44     }
45 }
46 int main(){
47     n=read();m=read();
48     build(1,n);
49     for(i=1;i<=m;i++){
50         id=read();L=read();R=read();
51         if(id)printf("%d\n",query(1,1,n));else change(1,1,n);
52     }
53     return 0;
54 }
View Code

 

 

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

  代码长度知一切系列。。直接模拟即可

1 #include<cstdio>
2 int n,ans;
3 int main(){
4     for(scanf("%d",&n);n>1;ans++)if(n&1)n=n*3+1;else n>>=1;printf("%d\n",ans);
5 }
View Code

 

bzoj 1724:[Usaco2006 Nov]Fence Repair 切割木板

  反过来看就是合并果子。。维护小根堆,每次把最短的两段木板并起来,直到变成一段

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<queue>
 5 #define ll long long
 6 using namespace std;
 7 priority_queue <ll>q;
 8 int i,j,k,n,m;
 9 ll ans,tmp;
10  
11 char rx;int ra;
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     n=read();
19     for(i=1;i<=n;i++)m=read(),q.push(-m);
20     for(i=1;i<n;i++){
21         tmp=q.top();q.pop();tmp+=q.top();q.pop();
22         ans-=tmp;q.push(tmp);
23     }
24     printf("%lld\n",ans);
25     return 0;
26 }
View Code

 

bzoj 1726:[Usaco2006 Nov]Roadblocks第二短路

  求严格次短路。。。最短路改一下。。同时记录到达某个点的最短距离和严格次短距离

  为了压常数把本来的代码长度改长了不少(反正本来也就毫无可读性= =)。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=5001;
 6 const int maxm=100002;
 7 int dis[2][maxn],last[maxn];
 8 struct zs{
 9     int too,dis;
10     int pre;
11 }e[maxm<<1];
12 short dl[23333];
13 bool u[maxn];
14 int i,j,k,n,m,a,b,c,tot;
15  
16 inline void insert(short a,short b,short c){
17     e[++tot].too=b;e[tot].dis=c;e[tot].pre=last[a];last[a]=tot;
18     e[++tot].too=a;e[tot].dis=c;e[tot].pre=last[b];last[b]=tot;
19 }
20 char rx;int ra;
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 void spfa(){
27     int l=0,r=1,now,i,a,b;
28     for(i=0;i<2;i++)memset(dis[i],50,(n+1)*4);
29     dl[1]=1;u[1]=1;dis[0][1]=0;short j;
30     while(l<r){
31         now=dl[++l];u[now]=0;
32         if(dis[0][now]<dis[1][n])
33         for(i=last[now],j=e[i].too,a=dis[0][now]+e[i].dis,b=dis[1][now]+e[i].dis;i;i=e[i].pre,j=e[i].too,a=dis[0][now]+e[i].dis,b=dis[1][now]+e[i].dis)
34             if(dis[0][j]>a){
35                 if(dis[0][j]<b)dis[1][j]=dis[0][j];else dis[1][j]=b;
36                 dis[0][j]=a;
37                 if(!u[j])u[j]=1,dl[++r]=j;
38             }else if(dis[0][j]<a) 
39                     if(a<dis[1][j]){
40                         dis[1][j]=a;
41                         if(!u[j])u[j]=1,dl[++r]=j;
42                     }else;
43              else if(dis[0][j]==a&&b<dis[1][j]){
44                 dis[1][j]=b;
45                 if(!u[j])u[j]=1,dl[++r]=j;
46             }
47     }
48 }
49 int main(){
50     n=read();m=read();
51     for(i=1;i<=m;i++)a=read(),b=read(),c=read(),insert(a,b,c);
52     spfa();
53     printf("%d\n",dis[1][n]);
54     return 0;
55 }
View Code

 

bzoj 1231:[Usaco2008 Nov]mixup2 混乱的奶牛

  题目是要求能使排列混乱的方案数。语死早。。数据范围显然状压。。

  f[i][j]表示当前已选入列奶牛的状态为i,最后一头牛编号为j的混乱方案数,(0<i<2^n,1<=j<=n)

  f[0][0]=1;f[i][j]=sum{f[i-2^j][k]},(S[k]-S[j]的绝对值>K,j存在于状态i中)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=16;
 7 ll f[16][(1<<maxn)+3],ans;
 8 int pos[(1<<maxn)+3];
 9 int two[17];
10 short a[17];
11 int x,y,x1,yy,j,K;
12 int mx;
13 int i,k,n;
14 bool can[17][17];
15 int main(){
16     scanf("%d%d",&n,&K);for(i=1;i<=n;i++)scanf("%d",&a[i]);
17     f[0][0]=1;mx=1<<n;
18     for(i=1;i<n;i++)for(j=i+1;j<=n;j++)if(max(a[i]-a[j],a[j]-a[i])>K)can[i-1][j-1]=can[j-1][i-1]=1;
19     for(i=1;i<=n;i++)two[i]=1<<(i-1),pos[two[i]]=i-1,f[i-1][two[i]]=1;
20     for(j=1;j<=mx&&j>0;j++)
21         for(x=j,y=x&(-x),i=pos[y];x;x-=y,y=x&(-x),i=pos[y])
22             for(x1=j,yy=x1&(-x1),k=pos[yy];x1;x1-=yy,yy=x1&(-x1),k=pos[yy])if(i!=k&&can[i][k])
23             f[k][j]+=f[i][j^yy];
24     for(i=0;i<n;i++)ans+=f[i][mx-1];
25     printf("%lld\n",ans);
26     return 0;
27 }
View Code

 

bzoj 1572: [Usaco2009 Open]工作安排Job

  按截止时间降序排序。也就是时间从大到小枚举,每个时间点安排价值最大、且截止时间在当前时间点之前的工作

  具体实现就不能一个一个时间点枚举了。。在相邻工作的截止时间之间的时间点,可以完成的工作都是不变的

  单调队列优化一下。

 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=100003;
 9 struct zs{
10     int tim,val;
11 }a[maxn];
12 priority_queue<int>q;
13 int i,j,k,n,m,top;
14 ll ans;
15 int ra,size;char rx;
16  
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 bool cmp(zs a,zs b){
23     return a.tim<b.tim;
24 }
25 int main(){
26     n=read();
27     for(i=1;i<=n;i++)a[i].tim=read(),a[i].val=read();
28     sort(a+1,a+1+n,cmp);
29      
30     for(i=n;i;i--){
31         q.push(a[i].val);size++;
32         if(a[i].tim-a[i-1].tim>size)j=size;else j=a[i].tim-a[i-1].tim;
33         while(j--)ans+=q.top(),q.pop(),size--;
34     }
35     printf("%lld\n",ans);
36     return 0;
37 }
View Code

 

bzoj 1579: [Usaco2009 Feb]Revamping Trails 道路升级

  分层图最短路。。。dis[i][j]表示到i点,共更新了j条边的最短路径长度。

  按照更新的边数建K+1层图,第i层表示当前更新了(i-1)条边。除了在本层内扩展外,第1~K层的点还可以向更高的一层扩展(更新当前边为0)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 #define ll long long
 6 using namespace std;
 7 const int maxn=10001;
 8 const int maxm=50001;
 9 const int mx=233333;
10 struct poi{
11     short pos;int dis;short int x;
12 }tmp;
13 priority_queue<poi>q;
14 struct zs{
15     short too;
16     int dis,pre;
17 }e[maxm<<1];
18 int last[maxn],dis[21][maxn];
19 ll dist[21][maxn],ans;
20 int i,j,k,n,m,K,tot,a,b;
21 bool u[21][maxn];
22  
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 bool operator <(poi a,poi b){return a.dis>b.dis;} 
30 void spfa(){
31     int l=0,r=1,i;short now;short int nowx;
32     for(i=0;i<=K;i++)memset(dist[i],50,(n+1)<<3);
33     ans=dist[0][n];
34     u[0][1]=1;dist[0][1]=0;
35     tmp.dis=0;tmp.pos=1;tmp.x=0;q.push(tmp) ;
36     while(!q.empty()){
37         tmp=q.top();q.pop();
38         now=tmp.pos;nowx=tmp.x;u[nowx][now]=0;
39         if(dist[nowx][now]<ans)
40         for(i=last[now];i;i=e[i].pre){
41             if(dist[nowx][e[i].too]>dist[nowx][now]+e[i].dis){
42                 dist[nowx][e[i].too]=dist[nowx][now]+e[i].dis;
43                 if(e[i].too==n)ans=min(ans,dist[nowx][e[i].too]);
44                 if(!u[nowx][e[i].too]){
45                     u[nowx][e[i].too]=1;
46                     tmp.pos=e[i].too;tmp.x=nowx;tmp.dis=dist[nowx][e[i].too];
47                     q.push(tmp);
48                 }
49             }
50             if(nowx<K&&dist[nowx+1][e[i].too]>dist[nowx][now]){
51                 dist[nowx+1][e[i].too]=dist[nowx][now];
52                 if(e[i].too==n)ans=min(ans,dist[nowx+1][e[i].too]);
53                 if(!u[nowx+1][e[i].too]){
54                     u[nowx+1][e[i].too]=1;
55                     tmp.pos=e[i].too;tmp.x=nowx+1;tmp.dis=dist[nowx+1][e[i].too];
56                     q.push(tmp);
57                 }
58             }
59         }
60     }
61 }
62 int main(){
63     n=read();m=read();K=read();
64     for(i=1;i<=m;i++){
65         a=read();b=read();
66         e[++tot].dis=e[tot+1].dis=read();
67         e[tot].too=b;e[tot].pre=last[a];last[a]=tot++;
68         e[tot].too=a;e[tot].pre=last[b];last[b]=tot;
69     }
70     spfa();
71     printf("%lld\n",ans);
72     return 0;
73 }
View Code

 

bzoj 1708: [Usaco2007 Oct]Money奶牛的硬币

  完全背包。。。一开始竟然没看出来王仓

 

bzoj 1690: [Usaco2007 Dec]奶牛的旅行

  01分数规划。。。二分答案为mid,将原图的边(u,v,time)重建为(u,v,fun[v]-time*mid),如果新图中有负环那么当前答案可行

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #define d double
 5 using namespace std;
 6 const int maxn=1021;
 7 const int maxm=5023;
 8 const d eps=1e-5;
 9 struct zs{
10     int too,pre,t;
11     d dis;
12 }e[maxm];
13 int i,j,k,n,m,tot,a,b,c;
14 d dist[maxn],l,r,mid;
15 int val[maxn],last[maxn];
16 bool u[maxn],uu[maxn],flag;
17  
18 inline int read(){
19     char x;int ans=0;
20     for(x=getchar();x<'0'||x>'9';x=getchar());
21     for(;x>='0'&&x<='9';x=getchar())ans*=10,ans+=x-48;
22     return ans;
23 }
24 inline void insert(int a,int b,int c){
25     e[++tot].too=b;e[tot].pre=last[a];e[tot].t=c;last[a]=tot;
26 }
27 bool spfa(int x){
28     u[x]=1;uu[x]=1;
29     for(int i=last[x];i;i=e[i].pre)if(dist[e[i].too]>dist[x]+e[i].dis){
30         dist[e[i].too]=dist[x]+e[i].dis;
31         if(u[e[i].too]){flag=1;return 1;}
32         if(spfa(e[i].too))return 1;
33     }
34     u[x]=0;
35     return 0;
36 }
37 bool check(d mid){
38     memset(uu,0,n+1);
39     memset(u,0,n+1);
40     memset(dist,0,4*(n+1));
41     flag=0;
42     for(int i=1;i<=n;i++)if(!uu[i])if(spfa(i))return 1;
43     return 0;
44 }
45 int main(){
46     n=read();m=read();
47     for(i=1;i<=n;i++)val[i]=read();
48     for(i=1;i<=m;i++)a=read(),b=read(),c=read(),insert(a,b,c),r=max(r,(d)val[b]/(d)c);
49     l=0.0;
50     while(l+eps<=r){
51         mid=(l+r)/2.0;
52         for(i=1;i<=m;i++)e[i].dis=(d)(-val[e[i].too])+mid*e[i].t;
53         if(check(mid))l=mid;else r=mid-eps;
54     }
55     printf("%.2lf\n",l);
56     return 0;
57 }
View Code

 

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

  字符串http://www.cnblogs.com/czllgzmzl/p/4989723.html

 

bzoj 1692: [Usaco2007 Dec]队列变换

  贪心。。。当前剩下的队伍为[l,r],每次比较 l到r 这段字符串和 r到l 这段字符串,哪段小选哪段

  比较字符串大小的时候可以用hash+二分求出最长公共前缀的长度,再比较下一位的大小

  hash用unsigned int不会被卡。。。感人。。明显优势#1

  然而O(n^2)暴力可过TAT

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ull unsigned int
 6 using namespace std;
 7 const int maxn=30003;
 8 char s[maxn];
 9 ull pre[maxn],jc[maxn],val1,val2,pre1[maxn];
10 short i,j,k,n,m,l,r,mid,len,L,R;
11  
12 inline short getlen(){
13     if(s[L]!=s[R])return 0;
14     l=1;r=R-L+1;
15     if(pre[L+r-1]-pre[L-1]*jc[r]==pre1[R-r+1]-pre1[R+1]*jc[r])return r;r--;
16     while(l<r){
17         mid=(l+r+1)>>1;//return mid;
18         val1=pre[L+mid-1]-pre[L-1]*jc[mid];
19         val2=pre1[R-mid+1]-pre1[R+1]*jc[mid];
20         if(val1!=val2)r=mid-1;else l=mid;
21         if(s[L+l]!=s[R-l])return l;
22     }
23     return l;
24 }
25 inline bool bigger(){
26     if(s[L]!=s[R])return s[L]>s[R];
27     len=getlen();
28     if(len==R-L+1)return 1;
29     else return s[L+len]>s[R-len];
30 }
31 int main(){
32     scanf("%d",&n);
33     for(i=1;i<=n;i++)for(s[i]=getchar();s[i]<'A'||s[i]>'Z';s[i]=getchar());
34     jc[0]=1;for(i=1;i<=n;i++)jc[i]=jc[i-1]*107;
35     for(i=1;i<=n;i++)pre[i]=pre[i-1]*107+(ull)s[i]-'A';
36     for(i=n;i;i--)pre1[i]=pre1[i+1]*107+(ull)s[i]-'A';
37     L=1;R=n;
38     for(i=1;i<=n;i++)if(bigger()){
39         putchar(s[R--]);
40         if(i%80==0)putchar('\n');
41     }else {putchar(s[L++]);if(i%80==0)putchar('\n');}
42     return 0;
43 }
View Code

 

bzoj 1782: [Usaco2010 Feb]slowdown 慢慢游

  dfs序,一头牛走到点i,相当于将点i所在子树的权值都+1,查询的时候查询牛要走到的点的权值

  也可以差分,变成点修改+区间查询,用树状数组就行了。。。

  太傻逼用线段树然后被常数感动哭了

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=140233;
 6 struct zs{
 7     int too,pre;
 8 }e[200122];
 9 int pos[100122],last[100233],size[100233];
10 int l[maxn<<1],r[maxn<<1],add[maxn<<1],A[maxn<<1],B[maxn<<1],mid[maxn<<1];
11 int i,j,k,n,m,a,b,c,tim,tot,tott;
12 int ra;char rx;
13  
14  
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     e[++tot].too=a;e[tot].pre=last[b];last[b]=tot;
23 }
24 void dfs(int x,int pre){
25     size[x]=1;pos[x]=++tim;
26     for(int i=last[x];i;i=e[i].pre)if(e[i].too!=pre){
27         dfs(e[i].too,x);size[x]+=size[e[i].too];
28     }
29 }
30 void build(int a,int b){
31     int now=++tott;
32     A[now]=a;B[now]=b;mid[now]=(a+b)>>1;
33     if(a<b){
34         l[now]=tott+1;build(a,mid[now]);
35         r[now]=tott+1;build(mid[now]+1,b);
36     }
37 }
38 inline void pushdown(int now){
39     add[l[now]]+=add[now];add[r[now]]+=add[now];
40     add[now]=0;
41 }
42 void insert(int now,int c,int d){
43     if(c<=A[now]&&B[now]<=d){add[now]++;return;}
44     if(add[now])pushdown(now);
45     if(c<=mid[now])insert(l[now],c,d);
46     if(d>mid[now])insert(r[now],c,d);
47 }
48 int query(int now,int c){
49     if(A[now]==B[now])return add[now];
50     if(add[now])pushdown(now);
51     if(c<=mid[now])return query(l[now],c);else return query(r[now],c);
52 }
53 int main(){
54     n=read();
55     for(i=1;i<n;i++)a=read(),b=read(),insert(a,b);
56     dfs(1,0);
57     build(1,n);
58     for(i=1;i<=n;i++){
59         a=read();printf("%d\n",query(1,pos[a]));
60         insert(1,pos[a],pos[a]+size[a]-1);
61     }
62 }
View Code

 

bzoj 1827: [Usaco2010 Mar]gather 奶牛大集会

  O(n^2)的暴力就是对每个点都把整棵树遍历一遍

  考虑一下,假设求出了到当前点i的不方便值为fasum,如何快速计算i的儿子的不方便值

  先预处理出每个点的子树内奶牛总数存在size[],那么对于i的某个儿子j,所有不在j的子树里的奶牛都得多走从i->j这段路,而j子树里的奶牛都可以少走i->j这段路

  nowsum=fasum+(cownum-size[j])*dis(i,j)-size[j]*dis(i,j);

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=100023;
 7 struct zs{
 8     int too,pre;
 9     ll dis;
10 }e[maxn<<1];
11 int size[maxn],last[maxn],tot,fa[maxn];
12 int i,j,k,n,m,a,b,poinum;
13 int ra;char rx;
14 ll nowsum,ans;
15  
16  
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 void dfs(int x,ll fasum){
23     for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa[x]&&size[e[i].too]<<1>poinum){
24         nowsum=fasum+(ll)(poinum-size[e[i].too]*2)*e[i].dis;
25         if(nowsum<ans)ans=nowsum;
26         dfs(e[i].too,nowsum);
27     }
28 }
29 void dfs1(int x){
30     for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa[x])
31         fa[e[i].too]=x,dfs1(e[i].too),size[x]+=size[e[i].too],nowsum+=(ll)size[e[i].too]*e[i].dis;
32 }
33 int main(){
34     n=read();
35     for(i=1;i<=n;i++)size[i]=read(),poinum+=size[i];
36     for(i=1;i<n;i++){
37         a=read();b=read();e[++tot].dis=e[tot+1].dis=read();
38         e[tot].too=b;e[tot].pre=last[a];last[a]=tot;
39         e[++tot].too=a;e[tot].pre=last[b];last[b]=tot;
40     }
41     dfs1(1);ans=nowsum;
42     dfs(1,nowsum);
43     printf("%lld\n",ans);
44     return 0;
45 }
View Code

 

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

  显然(看题解才知道的TAT)一段路修整后,高度一定和原来那些路中的某一段相等。。。。所以把高度离散化一下就变成O(n^2)的dp了。。。

  不下降的情况:f[i][j]表示前i段路,第i段高度修整为j的最小支出

          f[i][j]=min{ f[i-1][k]+abs(h[i]-h[j]) },(k<=j)转移的过程中顺便记录一下k就行了

  不上升就倒过来做一遍

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define uint unsigned int
 7 #define ll long long
 8 using namespace std;
 9 const int maxn=2005;
10 ll f[maxn][maxn],mn,ans;
11 int a[maxn],b[maxn];
12 int ra;char rx;
13 int i,j,k,n,m,nn;
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 short getpos(int x){
20     short l=1,r=nn,mid;
21     while(l<r){
22         mid=(l+r+1)>>1;
23         if(b[mid]<=x)l=mid;else r=mid-1;
24     }return l;
25 }
26 int main(){
27     n=read();for(i=1;i<=n;i++)a[i]=read();memcpy(b,a,(n+1)<<2);
28     sort(b+1,b+1+n);
29     nn=unique(b+1,b+1+n)-b-1;
30     for(i=1;i<=n;i++)a[i]=getpos(a[i]);
31     for(i=1;i<=n;i++)memset(f[i],50,(nn+1)<<3);ans=f[1][0];
32     for(i=1;i<=n;i++){mn=f[i-1][0];
33         for(j=1;j<a[i];j++){
34             if(f[i-1][j]<mn)mn=f[i-1][j];
35             f[i][j]=mn+b[a[i]]-b[j];
36         }
37         for(j=a[i];j<=nn;j++)mn=min(mn,f[i-1][j]),f[i][j]=mn+b[j]-b[a[i]];
38     }
39     for(i=1;i<=nn;i++)if(f[n][i]<ans)ans=f[n][i];
40       
41     for(i=1;i<=n;i++)memset(f[i],50,(nn+1)<<3);
42     for(i=1;i<=n;i++){mn=f[i-1][nn];
43         for(j=nn;j>a[i];j--){
44             if(f[i-1][j]<mn)mn=f[i-1][j];
45             f[i][j]=mn+b[j]-b[a[i]];
46         }
47         for(j=a[i];j;j--)mn=min(mn,f[i-1][j]),f[i][j]=mn+b[a[i]]-b[j];
48     }
49     for(i=1;i<=nn;i++)if(f[n][i]<ans)ans=f[n][i];
50     printf("%lld\n",ans);
51     return 0;
52 }
View Code

 

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

  数据范围就是状压了。。

  f[i][j]表示前i行,第i行种草状态为j的总方案数。

  f[i][j]=sum{ f[i-1][k] },j状态和k状态是合法的(没种到那一行贫瘠的土地,且没有草相邻),且j&k==0(没有上下两行没有草在同一列)

  预处理了各种非法情况结果比直接枚举慢= =

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const short maxn=13;
 6 const int modd=100000000;
 7 short two[maxn],mapl[maxn],mx;
 8 short map[(1<<12)+2][400];
 9 short i,j,k,n,m,tmp,now,pre;
10 int f[13][(1<<12)+1],ans;
11 char x;
12 int main(){
13     scanf("%d%d",&n,&m);
14     mx=1<<m;two[1]=1;
15     for(i=2;i<=m;i++)two[i]=two[i-1]<<1;
16     for(i=0;i<mx;i++){
17         bool flag=0;
18         for(j=1;j<m&&!flag;j++)if(i&two[j]&&i&two[j+1])flag=1;
19         if(!flag)map[0][++map[0][0]]=i;
20     }
21     for(i=1;i<mx;i++){
22         tmp=i-(i&(-i));
23         for(j=map[tmp][0];j;j--)if(!(map[tmp][j]&i))map[i][++map[i][0]]=map[tmp][j];
24     }
25     now=1;pre=0;
26     f[0][0]=1;
27     for(i=1;i<=n;i++){
28         now=i;pre=i-1;
29         for(j=1;j<=m;j++){for(x=getchar();x<'0'||x>'1';x=getchar());mapl[i]+=(x=='0')*two[j];}
30         for(j=map[0][0],tmp=map[0][j];j;j--,tmp=map[0][j])if(!(tmp&mapl[i-1])&&f[pre][tmp])
31             for(k=map[tmp][0];k;k--)if(!(map[tmp][k]&mapl[i]))
32                 f[now][map[tmp][k]]+=f[pre][tmp],f[now][map[tmp][k]]-=(f[now][map[tmp][k]]>=modd)?modd:0;
33     }
34     for(i=0;i<mx;i++)ans+=f[n][i],ans-=(ans>=modd)?modd:0;
35     printf("%d\n",ans);
36     return 0;
37 }
View Code

 

bzoj 1711:[Usaco2007 Open]Dingin吃饭

  二分图最大匹配。。s连奶牛,饮料和食品连t,每头牛往它要吃的东西连边。。。用dinic比匈牙利算法慢了点

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=103;
 6 struct zs{
 7     short too,flow;
 8     int pre;
 9 }e[100233];
10 short dis[423],dl[423];
11 short l,r,now;
12 int last[423],tot,s,t,n,m1,m2,num1,num2,a,i,j,ans;
13   
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(short a,short 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 bool bfs(){
25     memset(dis,255,(t+1)<<1);
26     l=0;r=1;dl[1]=s;dis[s]=0;
27     short now;int i;
28     while(l<r){
29         now=dl[++l];
30         for(i=last[now];i;i=e[i].pre)if(e[i].flow&&dis[e[i].too]==-1)
31             dl[++r]=e[i].too,dis[e[i].too]=dis[now]+1;
32     }
33     return dis[t]!=-1;
34 }
35 short dfs(short x,short mx){
36     if(!mx||x==t)return mx;
37     short w,used=0;int i;
38     for(i=last[x];i;i=e[i].pre)if(e[i].flow&&dis[e[i].too]==dis[x]+1){
39         w=dfs(e[i].too,min(mx-used,(int)e[i].flow));if(w){
40             e[i].flow-=w;e[((i-1)^1)+1].flow+=w;
41             used+=w;if(used==mx)return used;
42         }
43     }
44     dis[x]=-1;return used;
45 }
46 int main(){
47     n=read();m1=read();m2=read();s=0;t=n*2+m1+m2+1;
48     for(i=1;i<=n;i++){
49         insert(i+m1,i+m1+n);
50         num1=read();num2=read();
51         for(j=1;j<=num1;j++)a=read(),insert(a,i+m1);
52         for(j=1;j<=num2;j++)a=read(),insert(i+m1+n,a+m1+n*2);
53     }
54     for(i=1;i<=m1;i++)insert(0,i);
55     for(i=1;i<=m2;i++)insert(n*2+m1+i,t);
56     while(bfs())ans+=dfs(s,23333);
57     printf("%d\n",ans);
58     return 0;
59 }
View Code

 

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

  裸dp。f[i][j]表示走到第i列,第j行最大财富,

  f[1][1]=map[1][j];f[i][j]=max{f[i-1][j-1],f[i-1][j],f[i-1][j+1]}

  注意边界。。。。第0、n+1行和第1列初始化成负无穷QAQ

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxh=102;
 6 int map[maxh][maxh];
 7 int i,j,k,n,m,now,pre;
 8 int f[2][maxh];
 9 char x;
10 inline void read(int &ans){
11     x=getchar();int fh=1;
12     while((x<'0'||x>'9')&&x!='-')x=getchar();
13     if(x=='-')fh=-1,x=getchar();
14     while(x>='0'&&x<='9')ans*=10,ans+=x-48,x=getchar();ans*=fh;
15 }
16 int main(){
17     read(n);read(m);
18     for(i=1;i<=n;i++)for(j=1;j<=m;j++)read(map[i][j]);
19     f[0][1]=map[1][1];for(i=2;i<=n;i++)f[0][i]=-1023333333;
20     for(i=2;i<=m;i++){
21         pre=i&1;now=pre^1;f[pre][0]=f[pre][n+1]=-1023333333;
22         for(j=1;j<=n;j++)f[now][j]=max(f[pre][j],max(f[pre][j-1],f[pre][j+1]))+map[j][i];
23     }
24     printf("%d\n",f[now][n]);
25     return 0;
26 }
View Code

 

bzoj 1571: [Usaco2009 Open]滑雪课Ski

  dp,f[i][j]表示前i时间过后,能力值为j的最大滑雪次数

   f[i][j]=max{

    f[i-1][j],//开颓

    f[ i-Dmin[j] ][ j ]+1,//先把斜坡按所需能力排序,Dmin[j]表示 所需能力值<=j的斜坡中 所需最小时长

    g[ i-L[k] ],//上第k节课(前提是有课= =),g[i]表示f[i][1..100]中的最大值

  }

   代码丑得不忍直视。。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 const int maxn=10001;
 8 struct lesson{
 9     short st,l,val;
10 }a[101];
11 struct poi{
12     short need,cost;
13 }b[maxn];
14 short f[maxn][101],g[maxn],ans;
15 short cost[maxn],need[maxn],M[maxn],L[maxn],aa[101];
16 bool can[101];
17 int i,j,k,n,m,maxt,nn;
18 int ra;char rx;
19 inline int read(){
20     rx=getchar();ra=0;
21     while(rx<'0'||rx>'9')rx=getchar();
22     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
23 }
24 bool cmp(lesson a,lesson b){
25     return a.st<b.st;
26 }
27 bool cmp1(poi a,poi b){
28     return a.need<b.need;
29 }
30 bool cmp2(poi a,poi b){
31     return a.cost<b.cost;
32 }
33 inline short getpos(int x){
34     short l=1,r=nn,mid;
35     while(l<r){
36         mid=(l+r+1)>>1;
37         if(aa[mid]<=x)l=mid;else r=mid-1;
38     }
39     return l;
40 }
41 int main(){
42     maxt=read();n=read();m=read();
43     for(i=1;i<=n;i++)a[i].st=read(),a[i].l=read(),a[i].val=aa[i]=read();
44     sort(a+1,a+1+n,cmp);aa[n+1]=1;sort(aa,aa+2+n);nn=unique(aa+1,aa+2+n)-aa-1;//printf("   %d\n",nn);
45     for(i=1;i<=n;i++)a[i].val=getpos(a[i].val);
46     for(i=1;i<=m;i++)b[i].need=read(),b[i].cost=read();
47     sort(b+1,b+1+m,cmp1);int tmp=1,tmp1=b[1].cost;
48     for(i=2;i<=m;i++)if(b[i].cost<tmp1)tmp1=b[i].cost,b[++tmp].cost=b[i].cost,b[tmp].need=b[i].need;
49     m=tmp;
50     sort(b+1,b+1+m,cmp2);
51     int nowlesson=0,nowpoi=0;
52     memset(f[0],150,sizeof(f[0]));f[0][1]=0;can[1]=1;
53     for(i=1;i<=maxt;i++){
54         memcpy(f[i],f[i-1],(nn+1)<<1);
55         while(nowpoi<m&&b[nowpoi+1].cost<=i)nowpoi++;
56         while(nowlesson<n&&a[nowlesson+1].st+a[nowlesson+1].l==i)nowlesson++,f[i][a[nowlesson].val]=g[a[nowlesson].st],can[a[nowlesson].val]=1;
57         for(j=1;j<=nn;j++)if(can[j]){
58             for(k=1;k<=nowpoi;k++)if(aa[j]>=b[k].need&&f[i-b[k].cost][j]>=f[i][j])f[i][j]=f[i-b[k].cost][j]+1;
59     //      printf("%d %d    %d\n",i,j,f[i][j]);
60             if(f[i][j]>g[i])g[i]=f[i][j];
61         }//printf("   gi:%d\n",g[i]);
62     }
63     for(i=1;i<=nn;i++)ans=max(ans,f[maxt][i]);
64     printf("%d\n",ans);
65     return 0;
66 }
View Code

 

bzoj 1715: [Usaco2006 Dec]Wormholes 虫洞

  询问图中有没有负环。。。(回到过去必须是回到起点并且时间比出发时还早)

  dfs版的spfa判负环。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=502;
 6 const int maxm=5233;
 7 struct zs{
 8     short too,pre,dis;
 9 }e[maxm];
10 short i,j,k,n,m,tot,T,w,a,b;
11 short last[maxn];
12 int dis[maxn];
13 bool u[maxn],uu[maxn];
14 short ra;char rx;
15 inline short 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 dfs(short x){
21     short i,j;
22     uu[x]=u[x]=1;
23     for(i=last[x];i;i=e[i].pre)if(dis[e[i].too]>dis[x]+e[i].dis){
24         dis[e[i].too]=e[i].dis+dis[x];
25         if(u[e[i].too]||dfs(e[i].too)){u[x]=0;return 1;}
26     }u[x]=0;
27     return 0;
28 }
29 bool spfa(){
30     short j;
31     for(j=1;j<=n;j++)if(!uu[j]&&dfs(j))return 1;
32     return 0;
33 }
34 int main(){
35     T=read();
36     for(int ii=1;ii<=T;ii++){
37         n=read();m=read();w=read();
38         if(ii>1)memset(last,0,(n+1)<<1),memset(uu,0,n+1),tot=0;
39         for(i=1;i<=m;i++){
40             e[++tot+1].too=a=read();e[tot].too=b=read();e[tot].dis=e[tot+1].dis=read();
41             e[tot].pre=last[a];last[a]=tot++;
42             e[tot].pre=last[b];last[b]=tot;
43         }
44         for(i=1;i<=w;i++)a=read(),e[++tot].too=read(),e[tot].dis=-read(),e[tot].pre=last[a],last[a]=tot;
45         bool flag=spfa();
46         if(flag)printf("YES\n");else printf("NO\n");
47     }
48     return 0;
49 }
View Code

 

bzoj 1596: [Usaco2008 Jan]电话网络

  树形dp。。http://www.cnblogs.com/czllgzmzl/p/5064626.html

 

bzoj 2442: [Usaco2011 Open]修剪草坪

  单调队列。。

  最大效率==总效率-最小损失效率。f[i]表示前i头奶牛,因为不能有连续K只奶牛而损失的效率的最小值(第i头牛不安排)。

  f[i]=min{ f[j] } +E[i],(i-j<=K)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=100023;
 7 int dl[maxn];
 8 ll f[maxn],sum;
 9 int i,j,k,n,m,l,r;
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     n=read();k=read()+1;
18     l=r=1;dl[1]=0;
19     for(i=1;i<=n+1;i++){
20         while(l<r&&i-dl[l]>k)l++;
21         if(i<=n)j=read();else j=0;
22         f[i]=f[dl[l]]+j;sum+=j;
23         while(l<=r&&f[dl[r]]>=f[i])r--;
24         dl[++r]=i;
25     }
26     printf("%lld\n",sum-f[dl[l]]);
27     return 0;
28 }
View Code

 

bzoj 1233:  [Usaco2009Open]干草堆tower

  斜率优化。。。

  看了别人(似乎是wshjzaa?)题解才明白TAT  http://www.cnblogs.com/sagitta/p/4650681.html

  注:题解最后似乎有个地方<和>打反了?(或者是我语文不好。。)

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int maxn=100003;
 6 int f[maxn],pre[maxn],g[maxn];
 7 int i,j,k,n,m,l,r;
 8 int dl[maxn];
 9  
10 short ra;char rx;
11 inline short 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     scanf("%d",&n);
18     for(i=1;i<=n;i++)pre[i]=read()+pre[i-1];
19     l=r=1;dl[r]=n+1;
20     for(i=n;i;i--){
21         while(l<=r&&f[dl[l]]<=pre[dl[l]-1]-pre[i-1])l++;l--;
22         f[i]=pre[dl[l]-1]-pre[i-1];
23         g[i]=g[dl[l]]+1;
24         while(l<=r&&pre[dl[r]-1]-f[dl[r]]<=pre[i-1]-f[i])r--;
25         dl[++r]=i;
26     }
27     printf("%d\n",g[1]);
28     return 0;
29 }
View Code

 

bzoj 1707:  [Usaco2007 Nov]tanning分配防晒霜

  贪心。。http://www.cnblogs.com/czllgzmzl/p/5064620.html

 

bzoj 1709: [Usaco2007 Oct]Super Paintball超级弹珠

  难得的傻逼题。。可以O(n^3)无脑暴力。。。

  或者是先预处理一下,读入时处理出 每一行、每一列、每一条对角线的对手数量。。。当然还有每一个点上的对手数

  某个射击位置(x,y)能打到的对手数就是 第x行的对手数+第y行的对手数+所在两条对角线的对手数-3*((x,y)这个点上的对手数)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=105;
 7 int h[maxn],l[maxn],dj1[maxn<<1],dj2[maxn<<1],map[maxn][maxn];
 8 int i,j,k,n,m,ans,a,b;
 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<=m;i++)a=read(),b=read(),h[a]++,l[b]++,dj1[a+b-1]++,dj2[a-b+n]++,map[a][b]++;
18     for(i=1;i<=n;i++)for(j=1;j<=n;j++)
19     if(h[i]+l[j]+dj1[i+j-1]+dj2[i-j+n]-map[i][j]*3==m)ans++;
20     printf("%d\n",ans);
21     return 0;
22 }
View Code

 

bzoj 1576: [Usaco2009 Jan]安全路经Travel

  并查集正确姿势。。http://www.cnblogs.com/czllgzmzl/p/5064758.html

 

bzoj 1593: [Usaco2008 Feb]Hotel 旅馆

  比较正常的线段树题目。。。维护一段只有0和1的区间里面,最长的0的长度,从左边开始、从右边开始的最长的0的长度

  每次查找区间位置的时候,如果左子树里的够长就去左子树找,不然试试跨过左右子树的那段,最后才去右子树里找。(无解直接输出0)

  区间修改的话就维护一个标记,表示当前区间被覆盖的情况(客人订满、客人退空、已下传)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 const int maxn=66233;
 6 const int inf=1023333333;
 7 int mx[maxn<<1],l[maxn<<1],r[maxn<<1],lmx[maxn<<1],rmx[maxn<<1],size[maxn<<1],mid[maxn<<1],mxpos[maxn<<1];
 8 short cov[maxn<<1];//0:全可用,1:全不可,2:其他或已下传 
 9 int ra;char rx;
10 int i,j,k,n,m,ans,tot,L,R,id,pos;
11 inline void pushup(int now,int l,int r){
12     lmx[now]=lmx[l];if(lmx[l]==size[l])lmx[now]+=lmx[r];
13     rmx[now]=rmx[r];if(rmx[r]==size[r])rmx[now]+=rmx[l];
14     mx[now]=rmx[l]+lmx[r];mxpos[now]=mid[now]-rmx[l]+1;if(mx[l]>mx[now])mx[now]=mx[l],mxpos[now]=mxpos[l];if(mx[r]>mx[now])mx[now]=mx[r],mxpos[now]=mxpos[r];
15 }
16 void build(int a,int b){
17     int now=++tot;mid[now]=(a+b)>>1;
18     mx[now]=lmx[now]=rmx[now]=size[now]=b-a+1;mxpos[now]=a;cov[now]=2;
19     if(a<b){
20         l[now]=tot+1;build(a,mid[now]);
21         r[now]=tot+1;build(mid[now]+1,b);
22     }
23 }
24 inline void pushdown(int now,int l,int r){
25     if(cov[now]){
26         lmx[l]=lmx[r]=rmx[l]=rmx[r]=mx[l]=mx[r]=mxpos[r]=mxpos[l]=0;
27         cov[l]=cov[r]=1;
28     }else{
29         lmx[l]=rmx[l]=mx[l]=size[l];mxpos[l]=mid[now]-size[l]+1;
30         lmx[r]=rmx[r]=mx[r]=size[r];mxpos[r]=mid[now]+1;
31         cov[l]=cov[r]=0;
32     }
33     cov[now]=2;
34 }
35 void update(int now,int a,int b,int c,int d,int col){
36     if(c<=a&&d>=b){
37         cov[now]=col;
38         if(col)lmx[now]=rmx[now]=mx[now]=mxpos[now]=0;
39         else lmx[now]=rmx[now]=mx[now]=size[now],mxpos[now]=a;
40         return;
41     }
42     if(cov[now]!=2)pushdown(now,l[now],r[now]);
43     if(c<=mid[now])update(l[now],a,mid[now],c,d,col);
44     if(d>mid[now])update(r[now],mid[now]+1,b,c,d,col);
45     pushup(now,l[now],r[now]);
46 }
47 int getpos(int now,int a,int b,int len){
48     int L=l[now],R=r[now];
49     if(cov[now]!=2)pushdown(now,L,R);
50     if(mx[L]>=len)return getpos(L,a,mid[now],len);
51     else if(rmx[L]+lmx[R]>=len)return mid[now]-rmx[L]+1;
52     else return getpos(R,mid[now]+1,b,len);
53 }
54 inline int read(){
55     rx=getchar();ra=0;
56     while(rx<'0'||rx>'9')rx=getchar();
57     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
58 }
59 int main(){
60     n=read();m=read();
61     build(1,n);
62     for(i=1;i<=m;i++){
63         id=read();L=read();
64         if(id==1){
65             if(mx[1]>=L){
66                 pos=getpos(1,1,n,L);
67                 printf("%d\n",pos);
68                 update(1,1,n,pos,pos+L-1,1);
69             }else printf("0\n");
70         }else{
71             R=read();
72             update(1,1,n,L,L+R-1,0);
73         }
74     }
75     return 0;
76 }
View Code

  1A感人TAT

 

bzoj 1697: [Usaco2007 Feb]Cow Sorting牛排序

  置换群。。现在还是不会置换群QAQ。。。不过至少这题的题解看得懂QAQ。。。

  题解网上一坨。。因为poj里也有= =

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ll long long
 6 using namespace std;
 7 const int maxn=10023;
 8 struct zs{
 9     short pos;
10     int val;
11 }a[maxn];
12 short i,j,pos,n;
13 ll mn,ans,nowmn,nowsum,len;
14 bool u[maxn];
15  
16 bool cmp(zs a,zs b){
17     return a.val<b.val;
18 }
19 int ra;char rx;
20 inline int read(){
21     rx=getchar();ra=0;
22     while(rx<'0'||rx>'9')rx=getchar();
23     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
24 }
25 int main(){
26     n=read();
27     for(i=1;i<=n;i++)a[i].val=read(),a[i].pos=i;
28     sort(a+1,a+1+n,cmp);mn=a[1].val;
29     for(i=1;i<=n;i++)if(!u[i]){
30         u[i]=1;nowmn=nowsum=a[i].val;len=1;
31         for(pos=a[i].pos;!u[pos];pos=a[pos].pos){
32             len++,nowsum+=(ll)a[pos].val,u[pos]=1;
33             if(a[pos].val<nowmn)nowmn=a[pos].val;
34         }
35         ans+=nowsum+min((len-2)*nowmn,nowmn+(len+1)*mn);
36     }
37     printf("%lld\n",ans);
38     return 0;
39 }
View Code

 

bzoj 1828: [Usaco2010 Mar]balloc 农场分配

  把各个请求按右端点从小到大排序。。然后直接依次能满足的就满足。。。这样就行了。。。。至于为什么这样子贪心是对的。。TAT

  设区间左右端点为l[],r[]...

  因为是按r排序的:如果当前区间插入后会影响到后面的某个区间的话,那么相比于那个被影响的区间,插入当前区间更优。

           并且在插入当前区间前我们已经尽量满足了r更小的区间,所以当前区间对之前的区间无影响。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=132333;
 7 struct zs{
 8     int l,r;
 9 }a[maxn];
10 int mn[maxn<<1],l[maxn<<1],r[maxn<<1],mid[maxn<<1],tag[maxn<<1];
11 int ra;char rx;
12 int i,j,k,n,m,ans,tot;
13   
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;
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         if(mn[l[now]]<mn[r[now]])mn[now]=mn[l[now]];else mn[now]=mn[r[now]];
26     }else mn[now]=read();
27 }
28 bool cmp(zs a,zs b){
29     return a.r<b.r;
30 }
31 inline void pushdown(int now,int t){
32     tag[l[now]]+=t;tag[r[now]]+=t;
33     mn[l[now]]-=t;mn[r[now]]-=t;
34     tag[now]=0;
35 }
36 int query(int now,int a,int b,int c,int d){
37     if(c<=a&&d>=b)return mn[now];
38     if(tag[now])pushdown(now,tag[now]);
39     if(d<=mid[now])return query(l[now],a,mid[now],c,d);
40     else if(c>mid[now])return query(r[now],mid[now]+1,b,c,d);
41     else return min(query(l[now],a,mid[now],c,d),query(r[now],mid[now]+1,b,c,d));
42 }
43 void insert(int now,int a,int b,int c,int d){
44     if(c<=a&&d>=b){tag[now]++;mn[now]--;return;}
45     if(tag[now])pushdown(now,tag[now]);
46     if(c<=mid[now])insert(l[now],a,mid[now],c,d);
47     if(d>mid[now])insert(r[now],mid[now]+1,b,c,d);
48     mn[now]=min(mn[l[now]],mn[r[now]]);
49 }
50 int main(){
51     n=read();m=read();
52     build(1,n);
53     for(i=1;i<=m;i++)a[i].l=read(),a[i].r=read();
54     sort(a+1,a+1+m,cmp);
55     for(i=1;i<=m;i++)if(query(1,1,n,a[i].l,a[i].r)>0)ans++,insert(1,1,n,a[i].l,a[i].r);
56     printf("%d\n",ans);
57     return 0;
58 }
View Code

 

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

  就是求后继节点的总数。。。因为整张图是由若干个基环内向树组成,所以可以用tarjan缩点后做。。。

  不过因为是基环内向树(同今年noipD1T2)。。从某个点开始一直走就会把它所连向的环走遍,也就起到了缩点的效果。。

  具体就开个栈记录一下当前路径,记录一个点是否在栈中。注意已经求出后继节点数的点就不用再走了.

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int maxn=100001;
 5 int to[maxn],ans[maxn],st[maxn];
 6 bool ins[maxn];
 7 int i,j,n,m,top,ed,len,tmp;
 8 char s[6];
 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 inline void outx(int x){
16     for(tmp=0;x;x/=10)s[tmp++]=x%10;
17     for(register int i=tmp-1;i>=0;i--)putchar(s[i]+48);putchar('\n');
18 }
19 int main(){
20     n=read();
21     for(i=1;i<=n;i++)to[i]=read();
22     for(i=1;i<=n;i++)if(!ans[i]){
23         ins[i]=ans[i]=1;st[top=1]=i;
24         for(j=to[i];!ans[j]&&!ins[j];j=to[j])st[++top]=j,ins[j]=1;
25         if(ins[j]){
26             for(ed=j,j=top,len=1;st[j]!=ed;j--)len++;
27             for(;top>=j;top--)ans[st[top]]=len,ins[st[top]]=0;
28         }
29         while(top)ans[st[top]]=1+ans[to[st[top]]],ins[st[top--]]=0;
30     }
31     for(i=1;i<=n;i++)outx(ans[i]);
32     return 0;
33 }
View Code

//之前弄了半天依然被踩在#2。。。。知道刚刚才想到一个布尔数组不用开才弄到200ms。。。再加了个输出优化瞬间就176ms了= =感人肺腑

  

//为什么我每次用register int都更慢

 

bzoj 1754: [Usaco2005 qua]Bull Math

  高精度乘法。。。。。。。。。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int modd=10000;
 6 int a[23],b[23],ans[23],len;
 7 char s[44];
 8 short i,j;
 9 int main(){
10     scanf("%s",s);a[0]=1;
11     for(i=strlen(s),len=1;i;i--){
12         a[a[0]]+=(s[i-1]-'0')*len;
13         len*=10;if(len>=modd&&i>1)len=1,a[0]++;
14     }
15     scanf("%s",s);b[0]=1;
16     for(i=strlen(s),len=1;i;i--){
17         b[b[0]]+=(s[i-1]-'0')*len;
18         len*=10;if(len>=modd&&i>1)len=1,b[0]++;
19     }
20     len=a[0]+b[0];
21     for(i=1;i<=a[0];i++)for(j=1;j<=b[0];j++){
22         ans[i+j-1]+=a[i]*b[j];
23         if(ans[i+j-1]>=modd)ans[i+j]+=ans[i+j-1]/modd,ans[i+j-1]%=modd;
24     }
25     while(!ans[len]&&len>1)len--;
26     printf("%d",ans[len]);
27     for(i=len-1;i;i--){
28         for(j=10;j<modd;j*=10)if(ans[i]<j)putchar('0');
29         printf("%d",ans[i]);
30     }printf("\n");
31     return 0;
32 }
View Code

 

bzoj 1770: [Usaco2009 Nov]lights 燈

  高斯消元解异或方程组。。。。自由元就暴力枚举+最优性剪枝= =。。。

  话说自由元啊什么的一直不懂。。。数学方面以后再慢慢补吧(已经无数次这么说了TAT

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 short f[40][40],ans[40];
 6 int i,j,k,n,m,mn,a,b;
 7 int ra;char rx;
 8 inline int 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 void gauss(){
14     short i,j,k;
15     for(i=1;i<=n;i++){
16         for(j=i;j<=n&&!f[j][i];j++);if(j>n)continue;
17         if(i!=j)for(k=1;k<=n+1;k++)swap(f[i][k],f[j][k]);
18         for(j=1;j<=n;j++)if(i!=j&&f[j][i])
19             for(k=1;k<=n+1;k++)f[j][k]^=f[i][k];
20     }
21 }
22 void dfs(short now,int tot){
23     if(tot>=mn)return;
24     if(!now){
25         mn=tot;return;
26     }
27     if(f[now][now]){
28         short i;
29         ans[now]=f[now][n+1];
30         for(i=now+1;i<=n;i++)if(f[now][i])ans[now]^=ans[i];
31         dfs(now-1,tot+ans[now]);
32     }else{
33         ans[now]=0;dfs(now-1,tot);
34         ans[now]=1;dfs(now-1,tot+1);
35     }
36 }
37 int main(){
38     n=read();m=read();
39     for(i=1;i<=n;i++)f[i][i]=f[i][n+1]=1;
40     for(i=1;i<=m;i++)a=read(),b=read(),f[a][b]=f[b][a]=1;
41     gauss();
42     mn=1022223333;
43     dfs(n,0);
44     printf("%d\n",mn);
45     return 0;
46 }
View Code

  抄了黄学长代码。。捂脸

 

bzoj 1691: [Usaco2007 Dec]挑剔的美食家

  有点像bzoj1828。。。都是两个限定条件,虽然具体有点不同= =

  把奶牛按要求最低价升序排序,牧草按价格升序排序。

  枚举牧草,每种牧草让可接受它的奶牛中,对新鲜度要求最高的奶牛吃。

  具体就是用平衡树维护可接受当前价格的奶牛(会越来越多)的要求新鲜度。。每种牧草按新鲜度在树中找一下前驱。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #define ll long long
 7 using namespace std;
 8 const int maxn=100233;
 9 const int inf=1002333333;
10 struct gc{
11     int c,v;
12 }g[maxn],c[maxn];
13  
14 int t[maxn],l[maxn],r[maxn],rnd[maxn],sz[maxn];
15 int i,j,k,n,m,tot,rt,num;
16 ll ans;
17  
18 inline void lturn(int &x){
19     int R=r[x];r[x]=l[R];l[R]=x;x=R;
20 }
21 inline void rturn(int &x){
22     int L=l[x];l[x]=r[L];r[L]=x;x=L;
23 }
24 void insert(int &x,int val){
25     if(!x){x=++tot;t[x]=val;rnd[x]=rand();sz[x]=1;//printf("! cow v:%d  in\n",val);
26             return;
27     }
28     if(val==t[x])sz[x]++;
29      else if(val<t[x])
30          {insert(l[x],val);
31           if(rnd[l[x]]<rnd[x])rturn(x);
32     }else{insert(r[x],val);
33           if(rnd[r[x]]<rnd[x])lturn(x);
34     }
35 }
36 void del(int &x,int val){
37     if(t[x]==val){
38         //printf("!  deleting %d   v:%d\n",x,t[x]);
39         if(sz[x]>1)sz[x]--;
40         else if(!(l[x]&&r[x]))x=l[x]+r[x];//,printf("---->%d\n",x);
41         else if(rnd[l[x]]<rnd[r[x]]){rturn(x);del(x,val);}else {lturn(x);del(x,val);}
42     }else if(val<t[x])del(l[x],val);else del(r[x],val);
43 }
44 int find(int x,int val){if(!x)return 0;
45     if(t[x]>val)return find(l[x],val);else{
46         int tmp=find(r[x],val);
47         if(tmp)return tmp;else return t[x];
48     }
49 }
50 inline void read(int &ans){
51     char x=getchar();
52     while(x<'0'||x>'9')x=getchar();
53     while(x>='0'&&x<='9')ans*=10,ans+=x-48,x=getchar();
54 }
55 bool cmp(gc a,gc b){return a.c<b.c;}
56 int main(){
57     read(n);read(m);
58     if(m<n){printf("-1\n");return 0;};
59     for(i=1;i<=n;i++)read(c[i].c),read(c[i].v);
60     for(i=1;i<=m;i++)read(g[i].c),read(g[i].v);
61     sort(c+1,c+1+n,cmp);sort(g+1,g+1+m,cmp);j=rt=0;
62     for(i=1;i<=m&&m-i+1>=n-num&&num<n;i++){
63         while(j<n&&c[j+1].c<=g[i].c)j++,insert(rt,c[j].v);
64         int val=find(rt,g[i].v);
65         //printf("grass%d(%d %d)  be eaten by cow v:%d(%d %d)\n",i,g[i].c,g[i].v,val,,c[pos].v);
66         if(val)
67             num++,ans+=(ll)g[i].c,del(rt,val);
68                                 //,printf("%d(%d %d) eats  %d(%d %d)\n",pos,c[pos].c,c[pos].v,i,g[i].c,g[i].v);
69     }
70     if(num==n)
71     printf("%lld\n",ans);else printf("-1\n");
72     return 0;
73 }
View Code

  手打treap比调stl的慢= =

 

bzoj 1753: [Usaco2005 qua]Who's in the Middle

  如题。。。。。。。。。。。。。。。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=10001;
 7 int a[maxn],n,i;
 8  
 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();for(i=1;i<=n;i++)a[i]=read();
17     sort(a+1,a+1+n);
18     printf("%d\n",a[(n+1)>>1]);
19     return 0;
20 }
View Code

加了快速读入比没加的慢是什么情况= =

 

bzoj 1574: [Usaco2009 Jan]地震损坏Damage

  就是说对于报告的每个点,都要找到一圈点把它围起来(与1点阻断)。。显然(又是看题解才知道的QAQ)这一圈点就是那个点相邻的所有点(当然相邻点也可能是被报告的点,但总之这些点都无法到达了)。。

  因为圈内的点都无法到达,我们要使得圈上及圈内的点最少。。所以圈越小越好。。

  把每个报告的点的相邻节点都设为不可通过,最后统计下还能到达的点的数目就好。

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

 

bzoj 1584: [Usaco2009 Mar]Cleaning Up 打扫卫生

  DPhttp://www.cnblogs.com/czllgzmzl/p/5066443.html

 

bzoj 1710: [Usaco2007 Open]Cheappal 廉价回文

  因为最后要形成回文串。。。对于回文串来说删一个字母和 在对应位置添加一个同样的字母是等价的= =

  所以把一个字母和谐掉的代价是min(删除该字母费用,添加该字母费用)。。(记为cost[])

  接下来就是区间dp了。。。f[i][j]表示把原字符串中第i个~第j个字母变成回文串的最小代价。。原字符串为s

  f[i][j]=min{

    f[i][j-1]+cost[s[j]],f[i+1][j]+cost[s[i]],

    f[i+1][j-1],(s[i]==s[j])

  }最后答案就是f[1][m]

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=2033;
 6 char s[maxn],c[27];
 7 short cost[233],tmp;
 8 int f[maxn][maxn];
 9 short i,j,k,n,m,len;
10 short ra;char rx,trx;
11 inline short 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     n=read();m=read();
18     for(s[1]=getchar();s[1]<'a'||s[1]>'z';s[1]=getchar());
19     for(i=2;i<=m;i++)s[i]=getchar();
20     for(i=1;i<=n;i++){
21         for(trx=getchar();trx<'a'||trx>'z';trx=getchar());
22         tmp=read();cost[trx]=read();
23         if(tmp<cost[trx])cost[trx]=tmp;
24     }
25     for(len=2;len<=m;len++)for(i=m-len+1,j=m;i;i--,j--)
26         if(s[i]==s[j])f[i][j]=f[i+1][j-1];
27         else if(cost[s[j]]+f[i][j-1]<cost[s[i]]+f[i+1][j])f[i][j]=cost[s[j]]+f[i][j-1];
28         else f[i][j]=cost[s[i]]+f[i+1][j];
29     printf("%d\n",f[1][m]);
30     return 0;
31 }
View Code

 

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

  善用stl。。。善调bitset。。。

  按给出的大小关系建图。。求出每头牛i能确定的比它小的奶牛的数量num[i],答案就是 总对数-已知的关系对数。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<bitset>
 5 using namespace std;
 6 short too[1008][1008];
 7 bool u[1008],map[1008][1008];
 8 bitset<1008>a[1008];
 9 int i,j,k,n,m;
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 void dfs(int x){
17     u[x]=1;
18     for(short i=too[x][0];i;i--)if(!u[too[x][i]])dfs(too[x][i]),a[x]|=a[too[x][i]];
19     else a[x]|=a[too[x][i]];
20 }
21 int main(){
22     n=read();m=read();
23     for(i=1;i<=m;i++){
24         j=read(),k=read();
25         if(!map[j][k])map[j][k]=1,too[j][++too[j][0]]=k;
26     }
27     for(i=1;i<=n;i++)a[i][i]=1;
28     for(i=1;i<=n;i++)if(!u[i])dfs(i);
29     for(j=(n-1)*n/2+n,i=1;i<=n;i++)j-=a[i].count();
30     printf("%d\n",j);
31     return 0;
32 }
View Code

为啥同样是调bitset我就慢了这么多TAT

 

bzoj 1578: [Usaco2009 Feb]Stock Market 股票市场

  看了老司机的题解。。。http://www.cnblogs.com/JSZX11556/p/4664348.html

  引用:“我们假设每天买完第二天就卖掉( 不卖出也可以看作是卖出后再买入 ), 这样就是变成了一个完全背包问题了, 股票价格为体积, 第二天的股票价格 - 今天股票价格为价值.... 然后就一天一天dp...”。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxt=500012;
 6 int map[11][51],val,cost;
 7 int f[maxt];
 8 int i,j,k,n,m,T,nowt;
 9  
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     n=read();T=read();m=read();
18     for(i=0;i<n;i++)for(j=0;j<T;j++)map[j][i]=read();
19     for(nowt=1;nowt<T;nowt++){
20         if(nowt>1)memset(f,0,(m+1)<<2);
21         for(i=0;i<n;i++){
22             val=map[nowt][i]-map[nowt-1][i];cost=map[nowt-1][i];
23             if(val<=0)continue;
24             for(j=cost;j<=m;j++)if(f[j-cost]+val>f[j])f[j]=f[j-cost]+val;
25         }
26         m+=f[m];
27     }
28     printf("%d\n",m);
29     return 0;
30 }
View Code

 

bzoj 1598: [Usaco2008 Mar]牛跑步

  求第k短路。。看了kpm大爷的代码才知道可以懒出新境界。。。

  用优先队列维护spfa的队列(其实就变成了堆优化的dij)。。一个点出队k次时我们就得出了k短路。。。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 const int maxn=1002;
 7 struct zs{
 8     int dis,pos;
 9 };
10 struct edge{
11     int too,pre,dis;
12 }e[10023];
13 int dis[maxn],last[maxn],sumk[maxn];
14 int i,j,k,n,m,size,K,a;
15 priority_queue<zs>q;
16 bool operator <(zs a,zs b){
17     return a.dis>b.dis;
18 }
19  
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 int main(){
27     n=read();m=read();K=read();
28     for(i=1;i<=m;i++){
29         a=read();e[i].too=read();e[i].dis=read();
30         e[i].pre=last[a];last[a]=i;
31     }zs tmp;
32     size=1;tmp.pos=n;tmp.dis=0;q.push(tmp);
33     while(size&&sumk[1]<K){
34         i=q.top().pos;j=q.top().dis;size--;q.pop();
35         if(sumk[i]>=K)continue;
36         sumk[i]++;if(i==1){printf("%d\n",j);}
37         for(i=last[i];i;i=e[i].pre)tmp.pos=e[i].too,tmp.dis=j+e[i].dis,q.push(tmp),size++;
38     }
39     for(i=K-sumk[1];i;i--)puts("-1\n");
40     return 0;
41 }
View Code

 

bzoj 2060: [Usaco2010 Nov]Visiting Cows 拜访奶牛

  终于是傻逼题了。。。没有上司的舞会。树形dp,f[i][0]表示以i为根节点,i不选,能选的最多点数,f[i][1]表示以i为根节点,i选,能选的最多点数。

  f[i][0]=sum{ max(f[j][0],f[j][1]) },(j是i的儿子);f[i][1]=sum{ f[j][0] },(j是i的儿子)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=50023;
 6 struct zs{
 7     int too,pre;
 8 }e[maxn<<1];
 9 int last[maxn],f[maxn][2];
10 int i,j,n,m,tot,a,b;
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 void dfs(int x,int fa){
18     f[x][1]=1;
19     for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa){
20         dfs(e[i].too,x);
21         if(f[e[i].too][0]>f[e[i].too][1])f[x][0]+=f[e[i].too][0];else f[x][0]+=f[e[i].too][1];
22         f[x][1]+=f[e[i].too][0];
23     }
24 }
25 int main(){
26     n=read();
27     for(i=1;i<n;i++){
28         a=read();b=read();e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;
29         e[++tot].too=a;e[tot].pre=last[b];last[b]=tot;
30     }
31     dfs(1,0);
32     printf("%d\n",max(f[1][0],f[1][1]));
33     return 0;
34 }
View Code

 

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

  和bzoj4236那题思路一样。。。求得各种颜色数的前缀和,并差分。。如果两不同位置上差分后的结果相等,就说明这两个位置之间各种颜色数量相等。

  可以上hash。。。然而卡常无力被稳稳地踩了TAT

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn=100003;
 7 struct zs{
 8     int pos;
 9     unsigned int v;
10 }a[maxn];
11 int nownum[31],two[31];
12 bool u[maxn];
13 int i,j,k,n,m,kk,x,ans;
14 bool same;
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 bool cmp(zs a,zs b){
22     return a.v<b.v||(a.v==b.v&&a.pos<b.pos);
23 }
24 int main(){
25     n=read();k=read();two[1]=1;
26     for(i=1;i<k;i++)two[i+1]=two[i]<<1;
27     for(i=1;i<=n;i++){
28         x=read();
29         for(j=1;j<=k;j++)if(x&two[j])nownum[j]++;
30         for(j=1;j<k;j++)//a[i].num[j]=nownum[j]-nownum[j+1],
31             a[i].v*=233,a[i].v+=nownum[j]-nownum[j+1];
32         a[i].pos=i;
33     }
34     n++;
35     sort(a+1,a+1+n,cmp);
36     for(i=1;i<=n;){
37         for(j=i+1;j<=n&&a[i].v==a[j].v;j++);
38         j--;
39         if(a[j].pos-a[i].pos>ans)ans=a[j].pos-a[i].pos;
40         i=j+1;
41     }
42     printf("%d\n",ans);
43     return 0;
44 }
View Code

 

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

  如果K已经确定的话,可以O(n)求出最小判断次数M:从前往后扫一遍,如果一个点i上奶牛朝后站着,就把i~i+k-1头奶牛都转过来。因为此时不转的话以后就转不了了。。。

  注意无解的判定。。。如果第i头奶牛朝后站着且i+k>n(就是没有k头奶牛可以转了)就无解。。。

  区间修改,单点查询。。。这个可以用差分。。因为只有朝前和朝后两种,就直接异或一下就好了。时间复杂度O(n*k)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=5005;
 6 bool now[maxn],nowsum;
 7 int i,j,k,n,m,nowans,ans;
 8 bool mp[maxn];
 9 char rx;
10 int main(){
11     scanf("%d",&n);
12     for(i=1;i<=n;i++){
13         for(rx=getchar();rx!='F'&&rx!='B';rx=getchar());
14         mp[i]^=(rx=='B');
15         if(rx=='B')mp[i+1]^=1,ans++;
16     }
17     k=1;
18     for(i=2;i<=n;i++){
19         memcpy(now,mp,(n+1));nowans=nowsum=0;
20         for(j=1;j<=n&&nowans<ans;j++){
21             nowsum^=now[j];
22             if(nowsum&&j+i>n+1){nowans=102333333;break;}
23             if(nowsum)nowsum^=1,now[j+i]^=1,nowans++;
24         }
25         if(nowans<ans)ans=nowans,k=i;
26     }
27     printf("%d %d\n",k,ans);
28     return 0;
29 }
View Code

 

bzoj 1776: [Usaco2010 Hol]cowpol 奶牛政坛

  由题解可得(TAT)结论:某政党内部的最长路径一定有一个端点是政党内最深的一个点。。毕竟树的直径也有一个端点在叶子节点上?

  先一遍dfs求出每个政党最深的点,然后求它和所在政党其他点的距离的最大值。。树上两点间的距离dis(i,j)=depth[i]+depth[j]-depth[lca(i,j)]*2。。

  总时间复杂度O(nlogn)...求lca部分试了倍增和链剖两种。。。。代码长度差不多但是倍增慢多了QAQ

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=200233;
 6 const int maxdep=20;
 7 struct zs{
 8     int too,pre;
 9 }e[maxn<<1],map[maxn];
10 int last[maxn],dep[maxn],last1[maxn],mxpos[maxn],mxdep[maxn],bel[maxn],belong[maxn],size[maxn],fa[maxn];
11 int i,j,k,n,m,tot1,a,tot,K,b,ans,rt;
12   
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     map[++tot1].too=b;map[tot1].pre=last1[a];last1[a]=tot1;
21 }
22 void dfs(int x,int pre){
23     int i;size[x]=1;dep[x]=dep[pre]+1;fa[x]=pre;
24     if(dep[x]>mxdep[bel[x]])mxdep[bel[x]]=dep[x],mxpos[bel[x]]=x;
25     insert(bel[x],x);
26     for(i=last[x];i;i=e[i].pre)if(e[i].too!=pre)
27         dfs(e[i].too,x),size[x]+=size[e[i].too];
28 }
29 void dfs2(int x,int chain){
30     int i,k=0;belong[x]=chain;
31     for(i=last[x];i;i=e[i].pre)if(e[i].too!=fa[x]&&size[e[i].too]>size[k])k=e[i].too;
32     if(!k)return;
33     dfs2(k,chain);
34     for(i=last[x];i;i=e[i].pre)if(e[i].too!=fa[x]&&e[i].too!=k)dfs2(e[i].too,e[i].too);
35 }
36 inline int getlcadep(int a,int b){
37     for(;belong[a]!=belong[b];a=fa[belong[a]])if(dep[belong[a]]<dep[belong[b]])swap(a,b);
38     if(dep[a]<dep[b])return dep[a];else return dep[b];
39 }
40 int main(){
41     n=read();K=read();
42     for(i=1;i<=n;i++){
43         bel[i]=read();a=read();if(!a){rt=i;continue;}
44         e[++tot].too=i;e[tot].pre=last[a];last[a]=tot;
45         e[++tot].too=a;e[tot].pre=last[i];last[i]=tot;
46     }rt=n<4?n>>1:n>>2;
47     dfs(rt,0);dfs2(rt,rt);
48     for(i=1;i<=K;i++){
49         ans=0;
50         for(k=mxpos[i],j=last1[i];j;j=map[j].pre)ans=max(ans,dep[k]+dep[map[j].too]-(getlcadep(k,map[j].too)<<1));
51         printf("%d\n",ans);
52     }
53     return 0;
54 }
55 //链剖
View Code链剖
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=200233;
 6 const int maxdep=20;
 7 struct zs{
 8     int too,pre;
 9 }e[maxn<<1],map[maxn];
10 int last[maxn],depth[maxn],fa[maxn][maxdep],dep[maxn],last1[maxn],mxpos[maxn],mxdep[maxn],bel[maxn];
11 int i,j,k,n,m,tot1,a,tot,K,b,ans,rt;
12   
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     map[++tot1].too=b;map[tot1].pre=last1[a];last1[a]=tot1;
21 }
22 void dfs(int x,int pre){
23     int i;
24     dep[x]=dep[pre]+1;depth[x]=depth[pre];
25     if((dep[x]&(-dep[x]))==dep[x])depth[x]++;
26     if(dep[x]>mxdep[bel[x]])mxdep[bel[x]]=dep[x],mxpos[bel[x]]=x;
27     insert(bel[x],x);//printf("%d %d  %d %d\n",x,bel[x],dep[x],depth[x]);
28       
29     for(i=1;i<=depth[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];
30     for(i=last[x];i;i=e[i].pre)if(e[i].too!=pre)
31         fa[e[i].too][0]=x,dfs(e[i].too,x);
32 }
33 inline int getlca(int a,int b){
34     int i;
35     if(dep[a]<dep[b])swap(a,b);
36     for(i=depth[a];i>=0;i--)if(dep[fa[a][i]]>=dep[b])a=fa[a][i];
37     if(a!=b){
38         for(i=depth[a];i>=0;i--)if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
39         a=fa[a][0];
40     }
41     return a;
42 }
43 int main(){
44     n=read();K=read();
45     for(i=1;i<=n;i++){
46         bel[i]=read();a=read();if(!a){rt=i;continue;}
47         e[++tot].too=b=i;e[tot].pre=last[a];last[a]=tot;
48         e[++tot].too=a;e[tot].pre=last[b];last[b]=tot;
49     }depth[0]=-1;
50     dfs(rt,0);
51     for(i=1;i<=K;i++){
52         ans=0;
53         for(k=mxpos[i],j=last1[i];j;j=map[j].pre)ans=max(ans,dep[k]+dep[map[j].too]-(dep[getlca(k,map[j].too)]<<1));
54         printf("%d\n",ans);
55     }
56     return 0;
57 }
58 //倍增
View Code

 

bzoj 1700: [Usaco2007 Jan]Problem Solving 解题

  DP。。http://www.cnblogs.com/czllgzmzl/p/5068024.html

 

bzoj 1734: [Usaco2005 feb]Aggressive cows 愤怒的牛

  傻逼题。。二分答案+判定。。。。每次二分出一个答案mid后,贪心的划分,看一下能不能划出C段

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=100001;
 7 int a[maxn];
 8 int i,num,n,m,l,r,mid,pre;
 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     sort(a+1,a+1+n);
19     if(m==2){printf("%d\n",a[n]-a[1]);return 0;}
20     if(m==n){
21         for(l=a[n]-a[1],i=1;i<n;i++)if(a[i+1]-a[i]<l)l=a[i+1]-a[i];
22         printf("%d\n",l);return 0;
23     }
24     l=1;r=(a[n]-a[1])/(m-1);
25     while(l<r){
26         mid=(l+r+1)>>1;num=1;pre=a[1];
27         for(i=2;i<=n;i++)if(a[i]-pre>=mid)pre=a[i],num++;
28         if(num>=m)l=mid;else r=mid-1;
29     }
30     printf("%d\n",l);
31     return 0;
32 }
View Code

 

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

  二分图最大匹配。。。存在小行星(i,j),连一条i到j+n的边。

  dinic比匈牙利还是略慢。。

 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     bool flow;
 9 }e[23333];
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,233333333);
50     printf("%d\n",ans);
51     return 0;
52 }
View Code

 

bzoj 1705: [Usaco2007 Nov]Telephone Wire 架设电话线

  DPhttp://www.cnblogs.com/czllgzmzl/p/5068259.html

 

bzoj 1783: [Usaco2010 Jan]Taking Turns

  有点算博弈相关?http://www.cnblogs.com/czllgzmzl/p/5069730.html

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