2014/3/9 长沙多校(第二次)

A: 二分图着色/图中有奇圈

分析:难在思路上,如果对图论的算法掌握比较全面的话,看到这么大的n和multiply,应该想到o(n)的图搜索;

这道题应该判连通,但是数据很水,不判也过。二分图不能拿来判连通。

题源:http://acm.hdu.edu.cn/showproblem.php?pid=3478

代码:

 1 #include <iostream>
 2 #include <string.h>
 3 #include <vector>
 4 #include <queue>
 5 #include <stdio.h>
 6 #define maxn 100000+5
 7 using namespace std;
 8 vector<int> G[maxn];
 9 int T,n,m,s;
10 bool mark[maxn];
11 int color[maxn];
12 int nextint(){int x;scanf("%d",&x);return x;}
13 void read()
14 {
15     n=nextint();m=nextint();s=nextint();
16     for(int i=0;i<=n;i++)
17     G[i].clear();
18     for(int i=1;i<=m;i++)
19     {
20         int u,v;
21         u=nextint();
22         v=nextint();
23         G[u].push_back(v);
24         G[v].push_back(u);
25     }
26     return ;
27 }
28 bool BFS(int st)
29 {
30     bool odd=false;
31     int cnt=0;
32     queue<int> Q;
33     Q.push(st);
34     while(!Q.empty())
35     {
36         int k=Q.front();Q.pop();
37         if (mark[k]) continue;
38         cnt++;
39         mark[k]=true;
40         for(int i=0;i<G[k].size();i++)
41         {
42             int v=G[k][i];
43             if (mark[v] && color[k]==color[v]) odd=true;
44             color[v]=1-color[k];
45             Q.push(v);
46         }
47     }
48     if (odd && cnt==n) return true;else return false;
49 }
50 bool isok()
51 {
52     if (n==1) return true;
53     memset(mark,0,sizeof(mark));
54     memset(color,0,sizeof(color));
55     return BFS(s);
56 //    return DFS(0);
57 }
58 int main()
59 {
60     cin>>T;
61     for(int cas=1;cas<=T;cas++){
62         read();
63         if (isok())
64         printf("Case %d: YES
",cas);
65         else printf("Case %d: NO
",cas);
66     }
67     return 0;
68 }
View Code

E:排列组合

分析:写在代码中,注意坑:开long long,m==2的时候

题源:http://acm.hdu.edu.cn/showproblem.php?pid=3482

代码:

 1 /*
 2 分类讨论:
 3 N<M  M^N
 4 N=M  M+A(M,M)
 5 N>M  M+A(M,M)
 6 要注意:M==2时,ans=N^2
 7         M==1
 8         开long long
 9 */
10 #include <iostream>
11 #include <string.h>
12 #include <stdio.h>
13 #define Mod 987654321
14 
15 using namespace std;
16 int n,m;
17 int main()
18 {
19     while(cin>>n>>m && n>0 && m>0)
20     {
21         long long  ans=0;
22         if (m==1) {
23             ans=1;
24         }
25         else if (m==2) {
26             long long t=1;
27             for(int i=1;i<=n;i++) t=(t*2)%Mod;
28             ans=t;
29         }
30         else
31         {
32             if (n>=m){
33                 long long t=1;
34                 for(int i=1;i<=m;i++) t=(t*i)%Mod;
35                 ans=(m+t)%Mod;
36             }
37             else{
38                 long long t=1;
39                 for(int i=1;i<=n;i++) t=(t*m)%Mod;
40                 ans=t;
41             }
42         }
43         cout<<ans<<endl;
44     }
45     return 0;
46 }
View Code

G:枚举+模拟

分析:别忘了枚举这个有效手段,矩阵写在结构体中,更容易编码;网上有些只统计每行1的个数,判断相等或互补的方法是错的。

下面给组数据:

2 5
1 1 0 0 0
1 0 1 0 0

1 0 1 0 0
0 1 0 1 1

答案是No

题源:http://acm.hdu.edu.cn/showproblem.php?pid=3484

代码:

 1 #include<iostream>
 2 #include<string.h>
 3 #include<stdio.h>
 4 #include<vector>
 5 #define maxn 105
 6 using namespace std;
 7 
 8 int n,m;
 9 
10 int nextint(){int x;scanf("%d",&x);return x;}
11 
12 struct Matrix
13 {
14     int n,m;
15     int mat[maxn][maxn];
16     bool mark[maxn];
17     void init(int n,int m)
18     {
19         this->n=n;
20         this->m=m;
21     }
22     void print()
23     {
24         for(int i=1;i<=n;i++)
25         {
26             for(int j=1;j<=m;j++) cout<<mat[i][j]<<" ";
27             cout<<endl;
28         }
29     }
30     void read()
31     {
32         for(int i=1;i<=n;i++)
33         for(int j=1;j<=m;j++)
34         mat[i][j]=nextint();
35     }
36     void SwapColumn(int c1,int c2)
37     {
38         for(int i=1;i<=n;i++)
39         swap(mat[i][c1],mat[i][c2]);
40     }
41     void ChangeRow(Matrix M)
42     {
43         for(int i=1;i<=n;i++){
44             if (mat[i][1]!=M.mat[i][1])
45               for(int j=1;j<=m;j++) mat[i][j]=mat[i][j]^1;
46         }
47     }
48     bool check(Matrix M)
49     {
50         memset(mark,0,sizeof(mark));
51         for(int i=1;i<=m;i++)
52         {
53             bool ok=false;
54             for(int j=1;j<=m;j++)
55             {
56                 int cnt=0;
57                 if (mark[j]) continue;
58                 for(int l=1;l<=n;l++)
59                     if (M.mat[l][i]!=mat[l][j]) cnt++;
60                 if (!cnt) ok=true;
61             }
62             if (!ok) return false;
63         }
64         return true;
65     }
66 }M1,M2;
67 
68 int main()
69 {
70     while(cin>>n>>m && n>0 && m>0)
71     {
72         bool ans=false;
73         M1.init(n,m);M2.init(n,m);
74         M1.read();M2.read();
75         for(int i=1;i<=m;i++)
76         {
77             M1.SwapColumn(1,i);
78             M1.ChangeRow(M2);
79 //            M1.print();
80             if (M1.check(M2)) {
81                 ans=true; break;
82             }
83         }
84         if (ans) cout<<"Yes"<<endl;else cout<<"No"<<endl;
85     }
86     return 0;
87 }
View Code

H:dp

分析:dp[i][0],dp[i][1]:分别表示长度为i,以0,1结尾的串...

         注意 dp[i][1]=dp[i-1][0]+dp[i-1][1]-以10结尾的个数(dp[i-1][0]-dp[i-2][1])即可,边界写到dp[2]

题源:http://acm.hdu.edu.cn/showproblem.php?pid=3485

代码:

 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <cmath>
 5 #define maxn 10005
 6 
 7 using namespace std;
 8 
 9 int n;
10 int dp[maxn][2];
11 
12 void init()
13 {
14     dp[0][0]=0;dp[0][1]=0;
15     dp[1][0]=1;dp[1][1]=1;
16     dp[2][0]=2;dp[2][1]=2;
17     for(int i=3;i<maxn;i++)
18     {
19         dp[i][0]=dp[i-1][1]+dp[i-1][0];
20         dp[i][0]%=9997;
21         dp[i][1]=dp[i-1][1]+dp[i-2][0];
22         dp[i][1]%=9997;
23     }
24     return;
25 }
26 int main()
27 {
28     init();
29     while(cin>>n && n>=0)
30     {
31         printf("%d
",(dp[n][0]+dp[n][1])%9997);
32     }
33     return 0;
34 }
View Code

I:RMQ

分析:1m的时限太小了,需要优化(读入、记录搜索量)才能过,而且这道题也较有歧义,开始枚举每组的人数做,就一直W。

吐槽一下自己,这么经典的算法都不知道,明显在大白书上现成的模板啊。

题源:http://acm.hdu.edu.cn/showproblem.php?pid=3486

代码:

 1 /*I题:
 2 经典的RMQ算法,在白书的198页;
 3 d[i][j]指从i位置开头,长度为2^j的数字中最大/最小的数是多少
 4 j上限是lg2(R)*/
 5 #include <iostream>
 6 #include <string.h>
 7 #include <vector>
 8 #include <stdio.h>
 9 #include <stdlib.h>
10 #define maxn 200000+5
11 #define LL long long
12 using namespace std;
13 int d[maxn][20];
14 int A[maxn],n;
15 LL tar,ans;
16 
17 void read(int &d)
18 {
19     char ch;
20     while(ch=getchar(),ch<48||ch>57); d=ch-48;
21     while(ch=getchar(),ch<58&&ch>47) d=d*10+ch-48;
22 }
23 
24 void RMQ_init(){
25     memset(d,0,sizeof(d));
26     for(int i=0;i<n;i++) d[i][0]=A[i];
27     for(int j=1;(1<<j)<=n;j++)
28       for(int i=0;i+(1<<j)-1<n;i++)
29         d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
30 }
31 
32 LL RMQ(int L,int R)
33 {
34     int k=0;
35     while((1<<(k+1))<=R-L+1) k++;
36     return max(d[L][k],d[R-(1<<k)+1][k]);
37 }
38 
39 int main()
40 {
41     while(cin>>n>>tar && n>=0)
42     {
43         for(int i=0;i<n;i++) {
44             read(A[i]);
45         }
46         RMQ_init();
47         LL tot=0;int p_num=-1;ans=-1;
48         for(int i=1;i<=n;i++)//枚举组数
49         {
50             if (i*1000<=tar) continue;
51             int num=n/i,st=1;
52             if (p_num!=num) {//优化,记录上一次结果,可能组数改变,每组人数不变
53                 tot=0;st=1;
54             }else st=num*(i-1)+1;
55             for(int j=st;j+num-1<=num*i;j+=num)//j是每组的开头位置
56             {
57                 int  L=j,R=j+num-1;
58                 L--,R--;
59                 tot+=RMQ(L,R);//查询从0位开始
60             }
61             p_num=num;
62             if (tot>tar){
63                 ans=i;break;
64             }
65         }
66         printf("%d
",ans);
67     }
68     return 0;
69 }
View Code
原文地址:https://www.cnblogs.com/little-w/p/3590684.html