2013多校第二场

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code
原文地址:https://www.cnblogs.com/Rlemon/p/3215491.html