hdu 4611
题意:求累加abs(i%a - i%b)的和,(o<=i<n);
分析:首先a,b大小无关,不妨设a<b,通过枚举几项,发现按照每a个来分,abs(i%a-i%b)在大部分区间里的值是相同的,只有在k*b属于这个区间里的时候发生变化(因为余数都是递增的只有在k*b出现后从b-1变成0);
所以我们不妨枚举按长度为a来枚举起点,如果k*b属于这个区间就另外处理,当到达循环节后直接处理到最终余数部分继续枚举,最后如果大于n就break,并且减去多加的部分;
对于样例:21 2 5
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ..... 21
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0
每2个一组,每组的对应位置差值是相同,可以o(1)处理每一组,
第三组因为4在里面,所以分成两段,也可以o(1)处理,
处理到最小公倍数10后可以一次处理到20,然后继续处理,最坏的情况下a,b很大且互质,时间复杂度O(max(a,b));

1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 using namespace std; 8 const int N = 10000; 9 typedef long long LL; 10 int gcd(int a,int b){ 11 if (b==0) return a; 12 else return gcd(b,a%b); 13 } 14 int a,b,n; 15 int main(){ 16 int T;scanf("%d",&T); 17 while (T--){ 18 scanf("%d%d%d",&n,&a,&b); 19 if (a>b) swap(a,b); 20 int c = a/gcd(a,b)*b; 21 int now = 0,now2 = b; 22 LL ans = 0; 23 while (now < n){ 24 if (now <= now2 && now2 < now+a){ 25 ans +=(LL)abs(now%a-now%b)*(now2-now) + (LL)abs(now2%a-now2%b)*(now+a-now2); 26 now2 += b; 27 }else { 28 ans += (LL)abs(now%a-now%b)*a; 29 } 30 now += a; 31 if (now == c){ 32 ans = ans*(n/c); 33 now = n/c*c; 34 now2 = now + b; 35 } 36 } 37 if (now>=n){ 38 for (int i=now-1;i>=n;i--){ 39 ans -= abs(i%a-i%b); 40 } 41 printf("%I64d ",ans); 42 continue; 43 } 44 printf("%I64d ",ans); 45 } 46 return 0; 47 }
hdu 4614
题意:2个操作,操作1一个清空一段区间所有值,操作2一个从i位置开始找到空的位置就插入值,如果到末尾还有值没有插入完也结束;
分析:最终都转化为区间的更新,对于操作2只要二分找到最左边的起点和最右边的终点就可以了,基础的线段树区间更新;

1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 #define lson l,m,rt<<1 9 #define rson m+1,r,rt<<1|1 10 using namespace std; 11 const int N = 50000+10; 12 int col[N<<2],num[N<<2]; 13 int n,m; 14 void pushup(int rt){ 15 num[rt] = num[rt<<1] + num[rt<<1|1]; 16 } 17 void pushdown(int rt,int l,int m,int r){ 18 if (col[rt]!=-1){ 19 num[rt<<1] = col[rt] * (m-l+1); 20 num[rt<<1|1] = col[rt] * (r-m); 21 col[rt<<1] = col[rt<<1|1] = col[rt]; 22 col[rt] = -1; 23 } 24 } 25 void update(int L,int R,int c,int l,int r,int rt){ 26 if (L<=l && r<=R){ 27 col[rt] = c; 28 num[rt] = (r-l+1)*c; 29 return; 30 } 31 int m = (l+r)>>1; 32 pushdown(rt,l,m,r); 33 if (L<=m) update(L,R,c,lson); 34 if (m <R) update(L,R,c,rson); 35 pushup(rt); 36 } 37 int query(int L,int R,int l,int r,int rt){ 38 if (L<=l && r<=R){ 39 return num[rt]; 40 } 41 int m = (l+r)>>1; 42 pushdown(rt,l,m,r); 43 int t1=0,t2=0; 44 if (L<=m) t1 = query(L,R,lson); 45 if (m< R) t2 = query(L,R,rson); 46 return t1+t2; 47 } 48 int findl(int l,int r,int v){ 49 int ret; 50 int up = r; 51 while (r>=l){ 52 int m = (l+r)>>1; 53 int t = up-m+1-query(m,up,0,n-1,1); 54 55 if (t>=v){ 56 ret = m; l = m+1; 57 }else r = m-1; 58 } 59 return ret; 60 } 61 int findr(int l,int r,int v){ 62 int ret; 63 int lim = l; 64 while (r>=l){ 65 int m = (l+r)>>1; 66 int t = m-lim+1-query(lim,m,0,n-1,1); 67 if (t>=v){ 68 ret = m; r = m-1; 69 }else l = m+1; 70 } 71 return ret; 72 } 73 void solve(int u,int v){ 74 int c = query(u,n-1,0,n-1,1); 75 if (n-u==c){ 76 printf("Can not put any one. "); 77 return; 78 } 79 c = n-u-c; 80 int l = findl(u,n-1,c); 81 if (c>v) c = v; 82 int r = findr(u,n-1,c); 83 printf("%d %d ",l,r); 84 update(l,r,1,0,n-1,1); 85 } 86 int main(){ 87 int T;scanf("%d",&T); 88 while (T--){ 89 scanf("%d%d",&n,&m); 90 memset(col,-1,sizeof(col)); 91 memset(num,0,sizeof(num)); 92 for (int i=0;i<m;i++){ 93 int k,x,y; 94 scanf("%d%d%d",&k,&x,&y); 95 if (y>n-1) y = n-1; 96 if (x< 0 ) x =0; 97 if (k == 1){ 98 solve(x,y); 99 }else { 100 int c = query(x,y,0,n-1,1); 101 printf("%d ",c); 102 update(x,y,0,0,n-1,1); 103 } 104 } 105 printf(" "); 106 } 107 return 0; 108 }
hdu 4617
题意:给你n(<30)个无限长的圆柱,问圆柱之间最短的距离,如果相交就输出"LUCKY";
分析:因为圆柱是无限长的,于是圆柱间的最短距离就是两条轴线的最短距离(两条异面直线的距离),最后只要判断下是否大于还是小于两个圆柱底面半径和就好了
有板就行了。

1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<vector> 5 #include<cstdio> 6 #include<cstdlib> 7 using namespace std; 8 const double eps = 1e-8; 9 const int N =30+10; 10 inline int dcmp(double x){ 11 return x<-eps ? -1 : x>eps; 12 } 13 inline double sqr(double x){ 14 return x*x; 15 } 16 17 struct Point{ 18 double x,y,z; 19 Point(double x=0,double y=0,double z=0):x(x),y(y),z(z){} 20 Point operator + (const Point &p)const{ 21 return Point(x+p.x,y+p.y,z+p.z); 22 } 23 Point operator - (const Point &p)const{ 24 return Point(x-p.x,y-p.y,z-p.z); 25 } 26 Point operator * (const double &p)const{ 27 return Point(x*p,y*p,z*p); 28 } 29 Point operator / (const double &p)const{ 30 return Point(x/p,y/p,z/p); 31 } 32 void input(){ 33 scanf("%lf%lf%lf",&x,&y,&z); 34 } 35 36 }; 37 Point Cross(Point a,Point b){ 38 return Point(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z , a.x*b.y - a.y*b.x); 39 } 40 double Dot(Point a,Point b){ 41 return a.x*b.x+a.y*b.y+a.z*b.z; 42 } 43 double Length(Point a){ 44 return sqrt(Dot(a,a)); 45 } 46 bool LineDistance(Point p1,Point u,Point p2, Point v,double &s){ 47 double b = Dot(u,u)*Dot(v,v) - Dot(u,v)*Dot(u,v); 48 if (dcmp(b) == 0) return false; 49 double a = Dot(u,v)*Dot(v,p1-p2) - Dot(v,v)*Dot(u,p1-p2); 50 s = a/b; 51 return true; 52 } 53 double DistanceToLine(Point p,Point a,Point b){ 54 Point v1 = b - a, v2 = p - a; 55 return Length(Cross(v1,v2)) / Length(v1); 56 } 57 double Distance(Point a,Point b){ 58 return sqrt( sqr(a.x-b.x) + sqr(a.y-b.y) +sqr(a.z-b.z)); 59 60 } 61 Point ct[N],vec[N]; 62 double r[N]; 63 int n; 64 65 void solve(){ 66 double mx = 100000000; 67 68 for (int i =0;i<n;i++){ 69 for (int j=i+1;j<n;j++){ 70 double d,s; 71 if (LineDistance(ct[i],vec[i],ct[j],vec[j],s)){ 72 d = DistanceToLine(ct[i]+vec[i]*s,ct[j],ct[j]+vec[j]); 73 }else { 74 d = DistanceToLine(ct[i],ct[j],ct[j]+vec[j]); 75 } 76 d -= r[i]+r[j]; 77 if (d<mx) mx = d; 78 } 79 } 80 if (dcmp(mx)<=0) printf("Lucky "); 81 else printf("%.2lf ",mx); 82 83 } 84 int main(){ 85 int T;scanf("%d",&T); 86 while (T--){ 87 scanf("%d",&n); 88 for (int i=0;i<n;i++){ 89 ct[i].input(); 90 91 Point t1,t2; 92 t1.input(); t2.input(); 93 r[i]= Distance(ct[i],t1); 94 vec[i] = Cross(t1-ct[i],t2-ct[i]); 95 } 96 solve(); 97 } 98 return 0; 99 }
hdu 4618
题意:给你一个n*m(n,m<300)的矩阵,求最大子正方形,每行每列是回文串。
分析:为了出来方便,把矩阵构造一下,(按照manacher o(n)求回文串的方法)
预处理出每一行每一列以每个结点为中心最大的回文串;
然后在枚举每个点统计最大的回文正方形; 因为统计的时候复杂度就是O(N^3);
所以在预处理每一行的时候也可以直接O(N^3)暴力处理不需要用manacher的方法了;

1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<iostream> 5 #include<algorithm> 6 #include<vector> 7 #include<cmath> 8 using namespace std; 9 const int N = 600+10; 10 int mz[N][N]; 11 int n,m; 12 int c1[N][N],c2[N][N]; 13 int find(int x,int y){ 14 int k = 0; 15 int ret = 1; 16 int mx = 100000; 17 while (1){ 18 if (c1[x-k][y] >= ret && c1[x+k][y] >=ret && c2[x][y-k] >=ret && c2[x][y+k] >= ret){ 19 if (c1[x-k][y]<mx) mx = c1[x-k][y]; 20 if (c1[x+k][y]<mx) mx = c1[x+k][y]; 21 if (c2[x][y-k]<mx) mx = c2[x][y-k]; 22 if (c2[x][y+k]<mx) mx = c2[x][y+k]; 23 ret++; k++; 24 }else break; 25 if (ret >= mx) break; 26 } 27 return ret; 28 } 29 void solve(){ 30 for (int i = 0; i <= 2*n; i++){ 31 for (int j = 0; j <= 2*m; j++){ 32 int k = 0; 33 while (mz[i][j-k] == mz[i][j+k] && j-k>=0 && j+k<=2*m) k++; 34 c1[i][j] = k; 35 } 36 } 37 for (int i = 0; i <= 2*m; i++){ 38 for (int j = 0; j <= 2*n; j++){ 39 int k = 0; 40 while (mz[j+k][i] == mz[j-k][i] && j+k<=2*n && j-k>=0) k++; 41 c2[j][i] = k; 42 } 43 } 44 45 int ret = 0; 46 for (int i=0; i <= 2*n; i++){ 47 for (int j = 0; j <= 2*m; j++){ 48 int t = find(i,j); 49 if (t>ret) ret = t; 50 } 51 } 52 printf("%d ",ret-1); 53 54 } 55 int main(){ 56 int T;scanf("%d",&T); 57 while (T--){ 58 scanf("%d%d",&n,&m); 59 memset(mz,0,sizeof(mz)); 60 for (int i = 0; i < n; i++){ 61 for (int j = 0; j < m; j++){ 62 scanf("%d",&mz[i*2+1][j*2+1]); 63 } 64 } 65 solve(); 66 } 67 return 0; 68 }
hdu 4616
题意:给你一棵n-1个结点的树,每一结点有一个值ai[i],和一个bi[i]表示是否有陷阱,求最多经过m个陷阱能拿到的最大的价值,
题目要求一旦碰到第m个陷阱游戏就结束;
分析:就是从树上选一条链,链上的点是1的个数少于等于m个,如果等于m个那么至少一个端点要为1;
设dp[rt][i][j],i==0表示从点rt出发经历了j个陷阱且结束端点不是陷阱,能获得的最大价值,
i==1 表示从点rt出发经历了j个陷阱且结束端点是陷阱,能获得的最大价值;
dfs();扫一遍,边扫边处理出以该点为根的子树能得到的满足条件的最大值;
然后就变成一道模拟题了,我用了非常麻烦的写法,对每一种状态都人肉更新,特别是合并两条链的地方;其实应该有很多地方的转移是没必要的;

1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<iostream> 5 #include<algorithm> 6 #include<cmath> 7 #include<vector> 8 #pragma comment(linker, "/STACK:1024000000,1024000000") 9 using namespace std; 10 const int N = 50000+10; 11 vector<int > g[N]; 12 int dp[N][2][4]; 13 int n,m; 14 int ai[N],bi[N]; 15 inline void Max(int &x,int y){ 16 x = max(x,y); 17 } 18 int ans; 19 int find(int rt,int u,int v){ 20 int ret = 0; 21 if (bi[rt] == 0){ 22 if (m == 1){ 23 Max(ret, dp[u][0][0]+ai[rt]+dp[v][0][0]); 24 Max(ret, dp[u][1][1]+ai[rt]+dp[v][0][0]); 25 Max(ret, dp[u][0][0]+ai[rt]+dp[v][1][1]); 26 }else if (m == 2){ 27 Max(ret, dp[u][0][0]+ai[rt]+dp[v][0][0]); 28 Max(ret, dp[u][0][0]+ai[rt]+dp[v][0][1]); 29 Max(ret, dp[u][0][0]+ai[rt]+dp[v][1][1]); 30 Max(ret, dp[u][0][0]+ai[rt]+dp[v][1][2]); 31 32 Max(ret, dp[u][0][1]+ai[rt]+dp[v][0][0]); 33 Max(ret, dp[u][0][1]+ai[rt]+dp[v][1][1]); 34 Max(ret, dp[u][1][1]+ai[rt]+dp[v][0][0]); 35 Max(ret, dp[u][1][1]+ai[rt]+dp[v][0][1]); 36 Max(ret, dp[u][1][1]+ai[rt]+dp[v][1][1]); 37 38 Max(ret, dp[u][1][2]+ai[rt]+dp[v][0][0]); 39 40 }else if (m == 3){ 41 Max(ret, dp[u][0][0]+ai[rt]+dp[v][0][0]); 42 Max(ret, dp[u][0][0]+ai[rt]+dp[v][0][1]); 43 Max(ret, dp[u][0][0]+ai[rt]+dp[v][1][1]); 44 Max(ret, dp[u][0][0]+ai[rt]+dp[v][1][2]); 45 Max(ret, dp[u][0][0]+ai[rt]+dp[v][0][2]); 46 Max(ret, dp[u][0][0]+ai[rt]+dp[v][1][3]); 47 48 Max(ret, dp[u][0][1]+ai[rt]+dp[v][0][0]); 49 Max(ret, dp[u][0][1]+ai[rt]+dp[v][1][1]); 50 Max(ret, dp[u][0][1]+ai[rt]+dp[v][0][1]); 51 Max(ret, dp[u][0][1]+ai[rt]+dp[v][1][2]); 52 53 Max(ret, dp[u][1][1]+ai[rt]+dp[v][0][0]); 54 Max(ret, dp[u][1][1]+ai[rt]+dp[v][0][1]); 55 Max(ret, dp[u][1][1]+ai[rt]+dp[v][1][1]); 56 Max(ret, dp[u][1][1]+ai[rt]+dp[v][0][2]); 57 Max(ret, dp[u][1][1]+ai[rt]+dp[v][1][2]); 58 59 Max(ret, dp[u][1][2]+ai[rt]+dp[v][0][0]); 60 Max(ret, dp[u][1][2]+ai[rt]+dp[v][0][1]); 61 Max(ret, dp[u][1][2]+ai[rt]+dp[v][1][1]); 62 63 Max(ret, dp[u][1][3]+ai[rt]+dp[v][0][0]); 64 } 65 }else { 66 if (m == 1){ 67 Max(ret, dp[u][0][0]+ai[rt]); 68 Max(ret, dp[v][0][0]+ai[rt]); 69 70 }else if (m == 2){ 71 Max(ret, dp[u][0][0]+ai[rt]); 72 Max(ret, ai[rt]+dp[v][0][0]); 73 Max(ret, dp[u][0][0]+ai[rt]+dp[v][1][1]); 74 Max(ret, dp[u][0][0]+ai[rt]+dp[v][0][0]); 75 76 Max(ret, dp[u][0][1]+ai[rt]); 77 Max(ret, dp[u][1][1]+ai[rt]+dp[v][0][0]); 78 79 }else if (m == 3){ 80 Max(ret, dp[u][0][0]+ai[rt]); 81 Max(ret, ai[rt]+dp[v][0][0]); 82 Max(ret, dp[u][0][0]+ai[rt]+dp[v][1][1]); 83 Max(ret, dp[u][0][0]+ai[rt]+dp[v][0][0]); 84 Max(ret, dp[u][0][0]+ai[rt]+dp[v][0][1]); 85 Max(ret, dp[u][0][0]+ai[rt]+dp[v][1][2]); 86 87 Max(ret, dp[u][0][1]+ai[rt]); 88 Max(ret, dp[u][0][1]+ai[rt]+dp[v][1][1]); 89 90 Max(ret, dp[u][1][1]+ai[rt]+dp[v][0][0]); 91 Max(ret, dp[u][1][1]+ai[rt]+dp[v][0][1]); 92 Max(ret, dp[u][1][1]+ai[rt]+dp[v][1][1]); 93 94 Max(ret, dp[u][0][2]+ai[rt]); 95 Max(ret, dp[u][1][2]+ai[rt]+dp[v][0][0]); 96 } 97 } 98 return ret; 99 } 100 void dfs(int rt,int fa){//普通树形DP 101 if (bi[rt] == 0){ 102 dp[rt][0][0] = ai[rt]; 103 }else { 104 dp[rt][1][1] = ai[rt]; 105 dp[rt][0][1] = ai[rt]; 106 } 107 int sz = g[rt].size(); 108 for (int i = 0; i < sz; i++ ){ 109 int c = g[rt][i]; 110 if (c == fa) continue; 111 dfs(c, rt); 112 if (bi[rt] == 0){ 113 114 Max(dp[rt][0][0] , dp[c][0][0]+ai[rt]); 115 Max(dp[rt][0][1] , dp[c][0][1]+ai[rt]); 116 Max(dp[rt][1][1] , dp[c][1][1]+ai[rt]); 117 Max(dp[rt][0][2] , dp[c][0][2]+ai[rt]); 118 Max(dp[rt][1][2] , dp[c][1][2]+ai[rt]); 119 Max(dp[rt][0][3] , dp[c][0][3]+ai[rt]); 120 Max(dp[rt][1][3] , dp[c][1][3]+ai[rt]); 121 122 }else { 123 dp[rt][0][0] = 0; 124 Max(dp[rt][0][1] , dp[c][0][0]+ai[rt]); 125 dp[rt][1][1] = ai[rt]; 126 Max(dp[rt][0][2] , dp[c][0][1]+ai[rt]); 127 Max(dp[rt][1][2] , dp[c][1][1]+ai[rt]); 128 129 Max(dp[rt][0][3] , dp[c][0][2]+ai[rt]); 130 Max(dp[rt][1][3] , dp[c][1][2]+ai[rt]); 131 } 132 } 133 134 for (int i = 0; i < 2; i++){ 135 for (int j = 0; j < m; j++){ 136 Max(ans,dp[rt][i][j]); 137 } 138 } 139 Max(ans,dp[rt][1][m]); 140 if (bi[rt] == 1) Max(ans,dp[rt][0][m]);//处理出以rt为端点的链 141 for (int i = 0; i < sz; i++){//合并两条子链得到一条新链 142 int u = g[rt][i]; 143 for (int j = i+1; j < sz; j++){ 144 int v = g[rt][j]; 145 int t = find(rt,u,v); 146 Max(ans,t); 147 } 148 } 149 } 150 void solve(){ 151 ans = 0; 152 memset(dp,0,sizeof(dp)); 153 dfs(0,-1); 154 printf("%d ",ans); 155 } 156 int main(){ 157 int T; scanf("%d",&T); 158 while (T--){ 159 scanf("%d%d",&n,&m); 160 for (int i = 0; i < n; i++){ 161 scanf("%d%d",ai+i,bi+i); 162 } 163 for (int i = 0; i < n; i++) g[i].clear(); 164 for (int i = 0; i < n-1; i++){ 165 int u,v; 166 scanf("%d%d",&u,&v); 167 g[u].push_back(v); 168 g[v].push_back(u); 169 } 170 solve(); 171 } 172 return 0; 173 }
hdu 4619
题意:给你一个棋盘,然后放一些1*2或2*1的棋子,求不覆盖的情况下能放的最多个数;
分析:把棋盘按照(x+y)%2分成奇偶两类,显然一个棋子不管怎么放都会覆盖到一个奇数格子和偶数格子,
这样我们就就得到了一个二分图,一边是奇数格子一边是偶数格子,最大匹配就是所求的答案;

1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<iostream> 8 using namespace std; 9 const int N = 20000+10; 10 vector<int > g[N]; 11 int n,m; 12 int vis[N],dy[N]; 13 int find(int u,int tar){ 14 for (int i = 0; i < g[u].size(); i++){ 15 int c = g[u][i]; 16 if (vis[c] == tar) continue; 17 vis[c] = tar; 18 if (dy[c] == -1 || find(dy[c],tar)){ 19 dy[c] = u; 20 return 1; 21 } 22 } 23 return 0; 24 } 25 void solve(){ 26 int ret=0; 27 memset(dy,-1,sizeof(dy)); 28 memset(vis,0,sizeof(vis)); 29 int cnt= 0; 30 for (int i = N-1; i >= 0; i--){ 31 if (find(i,++cnt)) ret++; 32 } 33 printf("%d ",ret); 34 } 35 int main(){ 36 while (cin>>n>>m,n+m){ 37 for (int i = 0; i < N; i++) g[i].clear(); 38 for (int i = 0; i < n; i++) { 39 int x,y; cin>>x>>y; 40 if ((x+y)%2) g[x*101+y].push_back((x+1)*101+y); 41 else g[(x+1)*101+y].push_back(x*101+y); 42 } 43 for (int i = 0; i < m; i++) { 44 int x,y; cin>>x>>y; 45 if ((x+y)%2) g[x*101+y].push_back(x*101+y+1); 46 else g[x*101+y+1].push_back(x*101+y); 47 } 48 solve(); 49 } 50 return 0; 51 }
hdu 4612
题意:n个点m条边的图,问添加一条边使得桥最少;
分析:先边—双联通缩点(模板),然后变成一棵树,找树上最长路就可以了;

1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cstdlib> 5 #include<vector> 6 #include<algorithm> 7 #include<cmath> 8 #include<stack> 9 #pragma comment(linker, "/STACK:1024000000,1024000000") 10 #define pbk push_back 11 using namespace std; 12 const int N = 200000+10; 13 14 vector<int> G[N],G2[N]; 15 int n,m; 16 struct e_BCC{ 17 18 int n,pre[N],low[N],eccno[N],dfs_clock,ecc_cnt; 19 stack<int> S; 20 //vector<int > G;图太大会RE; 21 void init(int _n){ 22 n = _n; 23 for (int i = 1; i <= n; i++) G[i].clear(); 24 dfs_clock = ecc_cnt = 0; 25 memset(eccno,0,sizeof(eccno)); 26 memset(pre,0,sizeof(pre)); 27 while (!S.empty()) S.pop(); 28 29 } 30 void dfs(int u,int fa){ 31 pre[u] = low[u] = ++dfs_clock; 32 S.push(u); 33 bool first = 1; 34 int sz = G[u].size(); 35 for (int i = 0; i < sz; i++){ 36 int v = G[u][i]; 37 if (v == fa && first){ 38 first = 0; 39 continue; 40 } 41 if (!pre[v]){ 42 dfs(v,u); 43 low[u] = min(low[u], low[v]); 44 }else { 45 low[u] = min(low[u], pre[v]); 46 } 47 } 48 if (low[u] == pre[u]){ 49 ecc_cnt++; 50 while (1){ 51 int v = S.top(); S.pop(); 52 eccno[v] = ecc_cnt; 53 if (v == u) break; 54 } 55 } 56 } 57 void find_ecc(){ 58 for (int i = 1; i <= n; i++){ 59 if (!pre[i]) dfs(i,-1); 60 } 61 } 62 }H; 63 int vis[N],ans; 64 int dp[N]; 65 void dfs(int rt){ 66 int m1 = 0, m2 = 0; 67 dp[rt] = 0; 68 for (int i = 0; i < G2[rt].size(); i++){ 69 int c = G2[rt][i]; 70 if (vis[c]) continue; 71 vis[c] = 1; 72 dfs(c); 73 74 if (m1 == 0) m1 = dp[c]+1; 75 else if (dp[c]+1>=m1){ 76 if (m2 == 0 || m1>m2) m2 = m1; 77 m1 = dp[c]+1; 78 }else if (dp[c]+1>m2) m2 = dp[c]+1; 79 dp[rt] = max(dp[rt], dp[c] + 1); 80 } 81 82 ans = max(ans, m1 + m2); 83 } 84 void solve(){ 85 memset(vis,0,sizeof(vis)); 86 ans = 0; 87 vis[1] = 1; 88 dfs(1); 89 printf("%d ",H.ecc_cnt-ans-1); 90 } 91 int main(){ 92 while (~scanf("%d%d",&n,&m),n+m){ 93 H.init(n); 94 for (int i = 0; i < m; i++){ 95 int u,v; 96 scanf("%d%d",&u,&v); 97 G[u].pbk(v); G[v].pbk(u); 98 } 99 H.find_ecc(); 100 for (int i = 0; i <= H.ecc_cnt; i++) G2[i].clear(); 101 for (int i = 1; i <= n; i++){ 102 int u = H.eccno[i]; 103 for (int j = 0; j < G[i].size(); j++){ 104 int v = H.eccno[G[i][j]]; 105 G2[u].pbk(v); G2[v].pbk(u); 106 } 107 } 108 solve(); 109 } 110 return 0; 111 }
hdu 4620
题意:告诉你n刀可以切到的水果,和每刀切的时间,并且定义一刀切3个或3个以上为”好刀“,问最多连续的好刀数,并且连续相邻的切刀时间间隔不能超过w;
分析:暴搜,只要常数小一点就可以水过了,当然可以用十字链表优化搞下,代码是卡过的。

1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<vector> 7 #include<cstdlib> 8 using namespace std; 9 const int N = 30+10; 10 bool vis[210]; 11 vector<int > g[N]; 12 int ti[N],id[N]; 13 int n,m,w; 14 bool cmp(int x,int y){ 15 return ti[x]<ti[y]; 16 } 17 int ans; 18 int que[N]; 19 int ap[N]; 20 void dfs(int st,int cnt,int num,int dfs_clock){ 21 if (cnt>ans){ 22 ans = cnt; 23 memcpy(ap,que,sizeof(que)); 24 } 25 if (cnt+n-st<ans) return; 26 for (int i = st+1; i <= n; i++){ 27 if (st != 0 && ti[id[i]]-ti[id[st]]>w) break; 28 int u = id[i]; 29 int c = 0; 30 for (int j = 0; j < g[u].size(); j++){ 31 int s = g[u][j]; 32 if (vis[s] == 0){ 33 vis[s] = u; 34 c++; 35 } 36 } 37 if (c>=3){ 38 que[cnt+1] = id[i]; 39 dfs(i,cnt+1,num+c,dfs_clock+1); 40 } 41 for (int j = 0; j < g[u].size(); j++){ 42 int s = g[u][j]; 43 if (vis[s] == u){ 44 vis[s] = 0; 45 } 46 } 47 } 48 } 49 void solve(){ 50 memset(vis,0,sizeof(vis)); 51 sort(id+1,id+n+1,cmp); 52 ans = 0; 53 dfs(0,0,0,1); 54 55 printf("%d ",ans); 56 sort(ap+1,ap+ans+1); 57 for (int i = 1; i < ans; i++){ 58 printf("%d ",ap[i]); 59 } 60 printf("%d ",ap[ans]); 61 62 } 63 int main(){ 64 int T; scanf("%d",&T); 65 while (T--){ 66 scanf("%d%d%d",&n,&m,&w); 67 for (int i = 1; i <= n; i++) g[i].clear(); 68 for (int i = 1; i <= n; i++){ 69 int c; 70 id[i] = i; 71 scanf("%d%d",&c,ti+i); 72 for (int j = 0; j < c; j++){ 73 int u; scanf("%d",&u); 74 g[i].push_back(u); 75 76 } 77 } 78 solve(); 79 } 80 return 0; 81 }