UPD:我真不是想骗访问量TAT。。一开始没注意总长度写着写着网页崩了王仓(其实中午的时候就时常开始卡了= =)。。。。损失了2h(幸好长一点的都单独开了一篇)。。。。吓得赶紧分成两坨。。。。TAT。。。。。。。。。。。。。。
——————————————————————————————————————————————————————————————————————————————
写(被虐)了整整一个月b站上usaco的金组题。。。然而到现在总共只写了100道上下TAT(当然是按AC人数降序排列的了)(另外,是用云神的号写的= =毕竟三百大洋)
大概不到13是自己写的,一半是有大概方向后跑去看题解,剩下的就是毫无思路就去看题解作死的了= =
感觉金组题还是比较适合自己当前水平的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 ",f[n]); 45 return 0; 46 }
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(' '); 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 }
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 ",query(1,1,n));else change(1,1,n); 52 } 53 return 0; 54 }
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 ",ans); 5 }
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 ",ans); 25 return 0; 26 }
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 ",dis[1][n]); 54 return 0; 55 }
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 ",ans); 26 return 0; 27 }
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 ",ans); 36 return 0; 37 }
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 ",ans); 72 return 0; 73 }
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 ",l); 56 return 0; 57 }
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(' '); 41 }else {putchar(s[L++]);if(i%80==0)putchar(' ');} 42 return 0; 43 }
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 ",query(1,pos[a])); 60 insert(1,pos[a],pos[a]+size[a]-1); 61 } 62 }
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 ",ans); 44 return 0; 45 }
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 ",ans); 51 return 0; 52 }
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 ",ans); 36 return 0; 37 }
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 ",ans); 58 return 0; 59 }
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 ",f[now][n]); 25 return 0; 26 }
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 ",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 ",i,j,f[i][j]); 60 if(f[i][j]>g[i])g[i]=f[i][j]; 61 }//printf(" gi:%d ",g[i]); 62 } 63 for(i=1;i<=nn;i++)ans=max(ans,f[maxt][i]); 64 printf("%d ",ans); 65 return 0; 66 }
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 ");else printf("NO "); 47 } 48 return 0; 49 }
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 ",sum-f[dl[l]]); 27 return 0; 28 }
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 ",g[1]); 28 return 0; 29 }
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 ",ans); 21 return 0; 22 }
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 ",pos); 68 update(1,1,n,pos,pos+L-1,1); 69 }else printf("0 "); 70 }else{ 71 R=read(); 72 update(1,1,n,L,L+R-1,0); 73 } 74 } 75 return 0; 76 }
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 ",ans); 38 return 0; 39 }
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 ",ans); 57 return 0; 58 }
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(' '); 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 }
//之前弄了半天依然被踩在#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(" "); 31 return 0; 32 }
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 ",mn); 45 return 0; 46 }
抄了黄学长代码。。捂脸
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 ",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 ",x,t[x]); 39 if(sz[x]>1)sz[x]--; 40 else if(!(l[x]&&r[x]))x=l[x]+r[x];//,printf("---->%d ",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 ");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) ",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) ",pos,c[pos].c,c[pos].v,i,g[i].c,g[i].v); 69 } 70 if(num==n) 71 printf("%lld ",ans);else printf("-1 "); 72 return 0; 73 }
手打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 ",a[(n+1)>>1]); 19 return 0; 20 }
加了快速读入比没加的慢是什么情况= =
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-r); 35 return 0; 36 }
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 ",f[1][m]); 30 return 0; 31 }
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 ",j); 31 return 0; 32 }
为啥同样是调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 ",m); 29 return 0; 30 }
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 ",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 "); 40 return 0; 41 }
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 ",max(f[1][0],f[1][1])); 33 return 0; 34 }
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 ",ans); 43 return 0; 44 }
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 ",k,ans); 28 return 0; 29 }
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 ",ans); 52 } 53 return 0; 54 } 55 //链剖
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 ",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 ",ans); 55 } 56 return 0; 57 } 58 //倍增
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 ",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 ",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 ",l); 31 return 0; 32 }
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 ",ans); 51 return 0; 52 }
bzoj 1705: [Usaco2007 Nov]Telephone Wire 架设电话线
DPhttp://www.cnblogs.com/czllgzmzl/p/5068259.html
bzoj 1783: [Usaco2010 Jan]Taking Turns