1.N只老虎爱跳舞
- 题意分析:n个老虎,有m个关系,问有多少个老虎能确定排名?
- 解法:对每只老虎都分别向前向后搜索并返回数量,如果数量为n - 1,说明这个老虎相对于其他所有老虎的相等关系都知道,也就知道了它的排名了
- 代码:
#include<bits/stdc++.h> using namespace std; const int MAXN = 101; vector<int> in[MAXN]; vector<int> out[MAXN]; int fin(int i) { bool use[MAXN] = {0}; int sum = 0; queue<int> qu; qu.push(i); while(!qu.empty()) { int x = qu.front();qu.pop(); int end = in[x].size(); for(int j = 0;j < end;j++) if(use[in[x][j]] == 0) { use[in[x][j]] = 1; qu.push(in[x][j]); sum++; } } return sum; } int fout(int i) { bool use[MAXN] = {0}; int sum = 0; queue<int> qu; qu.push(i); while(!qu.empty()) { int x = qu.front();qu.pop(); int end = out[x].size(); for(int j = 0;j < end;j++) if(use[out[x][j]] == 0) { use[out[x][j]] = 1; qu.push(out[x][j]); sum++; } } return sum; } int main() { int n,m;cin >> n >> m; for(int i = 1;i <= m;i++) { int x,y;cin >> x >> y; in[x].push_back(y); out[y].push_back(x); } int sum = 0; for(int i = 1;i <= n;i++) { if(fin(i) + fout(i) == n - 1) sum++; } cout << sum; }
2.掩体计划
- 思路:将所有节点相连的最小花费即最小生成树问题(但在我写的时候我还不知道,紧急恶补了一下)
- 最小生成树的解法一般有两种:Kruskal和Prim
- (粗略地说)Kruskal算法为选最短的边,如果这两个点已经在一个集合里的话就舍弃,否则整合这两个集合并取这个边
- (粗略地说)Prim算法,随机挑选一个初始点作为已连接的点的集合,找最短的端点一个在集合内,一个在外的边,取这个边并且将那个在外的端点加入集合
- Kruskal代码:
#include<bits/stdc++.h> using namespace std; const int MAXN = 5e3 + 10,MAXM = 1e4 + 10; int n; int ptop = 1; struct link{ int x,y,v; }li[MAXM]; void add(int i,int j,int v) { li[ptop++] = {i,j,v}; } bool cmp(link a,link b) { return a.v < b.v; } int dad[MAXN]; void pre() { for(int i = 1;i <= n;i++) dad[i] = i; } int find(int x) { if(x == dad[x]) return x; else return dad[x] = find(dad[x]); } int main() { int m;cin >> n >> m; pre(); for(int i = 1;i <= m;i++) { int x,y,w;cin >> x >> y >> w; add(x,y,w); } sort(li + 1,li + m + 1,cmp); int sum = 0; for(int i = 1;i <= m;i++) { int x = li[i].x,y = li[i].y,w = li[i].v; if(find(x) != find(y)) { dad[find(y)] = find(x); sum += w; } } int t = 1; while(find(t) == find(t + 1)) { t++; if(t == n - 1) { cout << sum; return 0; } } cout << "Ridiculous! We can not combine city like a LOGO!!!"; }
3.你为什么不直接打死他?
- 应该是这里面最难的题了,虽然将思路写出来就感觉不怎么难了
- 思路:龙有三个状态,2血,1血,0血,用三进制来表示多个龙的状态,即状压dp,当然也可以加上滚动数组。
- 代码:
#include<bits/stdc++.h> using namespace std; int n,all,sum,l,be; double dp[60000][32]; int pow3[11]; int turn(int x) { int sum = 0; while(x != 0) { if(x % 3 != 0) sum++; x /= 3; } return sum; } void slove(int aim,int att,int sum) { dp[aim][att + 1] += dp[aim][att] / (sum + 1.0); int t = 0; int aa = aim; for(int i = 1;i <= n;i++) { if(aa % 3 != 0) dp[aim - pow3[t]][att + 1] += dp[aim][att] / (sum + 1.0); t++; aa /= 3; } } int main() { int m;cin >> n >> m; be = 0; pow3[0] = 1; for(int i = 1;i <= n;i++) { pow3[i] = pow3[i - 1] * 3; } for(int i = 1;i <= n;i++) { be *= 3; be += 2; } dp[be][0] = 1; for(int i = 0;i <= 3 * m;i++) { for(int j = 0;j <= be;j++) { int sum = turn(j);//剩下的人数 slove(j,i,sum); } } cout << dp[0][3 * m]; }
4.高维世界
- 暴力,没有一点感情(记得开long long)
- 代码:
#include<bits/stdc++.h> using namespace std; long long a[5001][11]; int main() { int n,k;cin >> n >> k; long long mi = -1; for(int i = 1;i <= n;i++) { for(int j = 1;j <= k;j++) cin >> a[i][j]; for(int j = 1;j < i;j++) { long long sum = 0; for(int kk = 1;kk <= k;kk++) sum += (a[i][kk] - a[j][kk]) * (a[i][kk] - a[j][kk]); if(sum < mi || mi == -1) mi = sum; } } cout << mi; }
5.牛牛坤卖手镯
- 经典最大子序列dp[i] = max(dp[i - 1] + a[i],a[i])
- 代码:
#include<bits/stdc++.h> using namespace std; long long a[5001][11]; int main() { int n,k;cin >> n >> k; long long mi = -1; for(int i = 1;i <= n;i++) { for(int j = 1;j <= k;j++) cin >> a[i][j]; for(int j = 1;j < i;j++) { long long sum = 0; for(int kk = 1;kk <= k;kk++) sum += (a[i][kk] - a[j][kk]) * (a[i][kk] - a[j][kk]); if(sum < mi || mi == -1) mi = sum; } } cout << mi; }
6.不废话了
- 数学题,看着很吓人
- 思路:首先 a & b <= min(a,b),然后⌊(a + b) / 2⌋ >= min(a,b),所以a & b == min(a,b) == ⌊(a + b) / 2⌋,根据后面的式子,假设a <= b,那么b <= a + 1,因为如果b >= a + 2,那么(a + b) / 2 > a,就不满足后式,然后又根据前式,a & b == a,说明a有的二进制位b都要有,如果b == a + 1,b又不进位,那么a只能是偶数。
- 这样一分,我们就让x / 2相等的作一堆来计算数量
- 代码:
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 10; long long a[MAXN]; //a & b <= min(a,b)? //(a + b) / 2 >= min(a,b)? //a == b == c? //.^. //偶数与偶数加1为一组 map<long long,long long> mp; long long turn(long long x) { return x * (x - 1) / 2 * (x - 2) / 3; } int main() { int n,m;cin >> n >> m; long long sum = 0; for(int i = 1;i <= n;i++) { cin >> a[i]; a[i] /= 2; mp[a[i]]++; if(mp[a[i]] >= 3) sum += turn(mp[a[i]]) - turn(mp[a[i]] - 1); } for(int i = 1;i <= m;i++) { int x,y;cin >> x >> y; y /= 2; if(mp[a[x]] >= 3) sum -= turn(mp[a[x]]) - turn(mp[a[x]] - 1); mp[a[x]]--; a[x] = y; if(++mp[y] >= 3) sum += turn(mp[y]) - turn(mp[y] - 1); cout << sum << endl; } }
7.阶梯计划
- 首先一看,将必须品取出后0/1背包找最高价值,但是容量范围过大,又一看价值的范围比较小,那么我们就反过来想,对体积进行0/1背包找出对应价值下的最大剩余容量,如果最大剩余容量大于等于0那么说明这个价值可取,再取价值的最大值
- 代码:
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e3 + 10,MAXV = 1e4 + 10; int www[MAXN],v[MAXN]; int dp[MAXV]; bool able[MAXV] = {0}; int main() { int w,n;cin >> w >> n; int nn = 0; for(int i = 1;i <= n;i++) { int ww,vv;cin >> ww >> vv; if(vv == -1) { w -= ww; } else { www[++nn] = ww; v[nn] = vv; } } dp[0] = w; able[0] = 1; int mv = 0; int mvv = 0; for(int j = 1;j <= nn;j++) { mv += v[j]; for(int i = min(MAXV - 1,mv);i >= v[j];i--) { if(able[i - v[j]]) if(dp[i] <= dp[i - v[j]] - www[j]) { dp[i] = dp[i - v[j]] - www[j]; able[i] = 1; mvv = max(i,mvv); } } } if(mvv == 0) cout << "failed!"; else cout << mvv; }
8.修复磁盘
- 弹 弹 乐 ?
- 思路:分为4种可能,直接能到,向左弹后能到,向右弹后能到,不能到,思路好想但公式比较难写出
- 代码:
#include<bits/stdc++.h> using namespace std; int main() { int t;cin >> t; for(int i = 1;i <= t;i++) { int n,x,y,d;cin >> n >> x >> y >> d; if(abs(x - y) % d == 0) cout << abs(x - y) / d << endl; else { long long mi = -1; if((y - 1) % d == 0) mi = (y - 1) / d + 1 + (x - 1) / d; if((n - y) % d == 0) if(mi > (n - y) / d + 1 + (n - x) / d || mi == -1) mi = (n - y) / d + 1 + (n - x) / d; cout << mi << endl; } } }
9.鱼饵桶
- 又是炉石
- 分为两个,总和最大和单独最大,单独最大肯定是挑最大的再加最多的BUFF
- 总和最大推一下公式就出来了(记得开long long)
- 代码:
#include<bits/stdc++.h> using namespace std; int main() { long long n,m;cin >> n >> m; long long damage = 0,hp = 0,sumdamage = 0,sumhp = 0; for(int i = 1;i <= n;i++) { long long x,y;cin >> x >> y; if(x > damage) damage = x; if(y > hp) hp = y; sumdamage += x; sumhp += y; } long long ma = m * (1 + (n - 1) / 2) * (n - (n - 1) / 2); cout << sumdamage + ma << ' ' << sumhp + ma << ' ' << damage + n * m << ' ' << hp + n * m; }
10.口吃症
- 水
- 代码:
#include<bits/stdc++.h> using namespace std; int main() { int n;cin >> n; int m; for(int i = 1;i <= 10;i++) { if((i + 1) * i / 2 == n) m = i; } int t = -1; string str;cin >> str; for(int i = 1;i <= m;i++) { t += i; cout << str[t]; } }
11.等座位
- 也挺水的,记录区间位置再二分即可
- 代码:
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 10; int st[MAXN]; int main() { int n,m;cin >> n >> m; for(int i = 1;i <= n;i++) { int x;cin >> x; st[i] = st[i - 1] + x; } for(int i = 1;i <= m;i++) { int x;cin >> x; int begin = 1,end = n; int ans = 1; while(begin <= end) { int mid = (begin + end) / 2; if(st[mid] >= x) { ans = mid; end = mid - 1; } else begin = mid + 1; } cout << ans << endl; } }
12.玩游戏
- 最大公约数,辗转相除法,模拟,水
- 代码:
#include<bits/stdc++.h> using namespace std; int gcd(int x,int y) { if(y == 0) return x; else if(x == 0) return y; return gcd(y,x % y); } int main() { int a,b,n;cin >> a >> b >> n; int type = 0; while(1) { if(gcd(a,n) <= n) n -= gcd(a,n); else { type = 1; break; } if(gcd(b,n) <= n) n -= gcd(b,n); else { type = 2; break; } } if(type == 1) cout << "xiao hua win!"; else cout << "xiao peng win!"; }
13.环球旅行
- 就暴力搜索
- 代码:
#include<bits/stdc++.h> using namespace std; //最小环,但是节点固定 //搜索 int n,num,be,mi; bool able[11]; bool use[11]; int l[11][11]; void DFS(int x,int sum,int nn) { if(nn == num) { if(l[be][x] != 0) if(mi != -1) mi = min(sum + l[be][x],mi); else mi = sum + l[be][x]; } else { for(int i = 1;i <= n;i++) if(able[i] && !use[i] && l[x][i] != 0) { use[i] = 1; DFS(i,sum + l[x][i],nn + 1); use[i] = 0; } } } void pre() { mi = -1; for(int i = 1;i <= n;i++) able[i] = use[i] = 0; } int main() { int m;cin >> n >> m; for(int i = 1;i <= m;i++)//录入 { int x,y,t;cin >> x >> y >> t; if(l[x][y] == 0) l[x][y] = l[y][x] = t; else l[x][y] = l[y][x] = min(l[y][x],t); } int q;cin >> q; for(int i = 1;i <= q;i++) { pre();//初始化 cin >> num; for(int j = 1;j <= num;j++) { cin >> be;able[be] = 1;//标记可以走 } use[be] = 1;//标记起点 DFS(be,0,1); cout << mi << endl; } }