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