下面的题解按照难度排序。
T1
果断枚举坐标就行了 。
时间复杂度是 O
#include <bits/stdc++.h> using namespace std; const int MAXN = 205; double dis[MAXN],x[MAXN],y[MAXN]; int n; double calc(double X1,double Y1, double X2, double Y2) { return sqrt((X2 - X1) * (X2 - X1) + (Y2 - Y1) * (Y2 - Y1)); } int main() { cin >> n; for(int i = 1 ; i <= n ; i ++) cin >> x[i] >> y[i]; for(int i = 1 ; i <= 200 ; i ++) { for(int j = 1 ; j <= 200 ; j ++) { double X = double(i) , Y = double(j); for(int k = 1 ; k <= n ; k ++) dis[k] = calc(x[k],y[k],X,Y); int flag = 0; for(int k = 1 ; k <= n ; k ++) if(abs(dis[k] - dis[1]) > 0.0001) flag = 1; if(flag == 0) {cout << i << " " << j << endl; return 0;} } } cout << "War is cruel."; return 0; }
T2
观察题目后,不难想到把原数组按照战力从大到小排序。
然后映射,对于排序后的数组映射为每一个数在原数组中的下标。
假设原数组中第 大的是在第 大的后面,那么显然答案是要 + 1的,因为这就得删去第 大的后重新来一轮。
我们发现只需要判断映射后的数组中有多少个 即可。
最后的答案要 + 1,因为无论如何至少要进行一轮。
#include <bits/stdc++.h> using namespace std; const int MAXN = 8e5 + 50; bool book[MAXN + MAXN / 4]; int n,A[MAXN]; struct Node { int data,id; bool operator < (const Node &Q) { return Q.data < data; } } T[MAXN]; inline int read() { int x = 0 , flag = 1; char ch = getchar() ; for( ; ch > '9' || ch < '0' ; ch = getchar()) ; for( ; ch >= '0' && ch <= '9' ; ch = getchar()) x = (x << 3) + (x << 1) + ch - '0'; return x * flag; } int main() { n = read(); for(int i = 1 ; i <= n ; i ++) A[i] = read(); for(int i = 1 ; i <= n ; i ++) T[i].data = A[i] , T[i].id = i; sort(T + 1 , T + 1 + n ); int Ans = 0; for(int i = 1 ; i <= n ; i ++) if(T[i].id > T[i + 1].id) Ans ++; cout << Ans; return 0; }
T4
不难发现,要求经过的边最少,那么就是一棵生成树。
要求权值最小,那么就是最小生成树。
观察到在一棵树里面能够保证每条边恰好被经过两次(根据欧拉序可知)。
所以最后的答案就是最小生成树的权值 * 2。
#include <bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 50; int n,m,cnt = 0; int start[MAXN],f[MAXN]; struct Edge { int to,from,w; } edge[MAXN * 10]; inline int read() { int x = 0 , flag = 1; char ch = getchar() ; for( ; ch > '9' || ch < '0' ; ch = getchar()) ; for( ; ch >= '0' && ch <= '9' ; ch = getchar()) x = (x << 3) + (x << 1) + ch - '0'; return x * flag; } void add(int u,int v,int w) { edge[++cnt].from = u; edge[cnt].to = v; edge[cnt].w = w; return ; } int find(int x) { if(f[x] != x) f[x] = find(f[x]); return f[x]; } bool cmp(Edge AA, Edge BB) { return AA.w < BB.w; } int main() { n = read() , m = read(); for(int i = 1 ; i <= n ; i ++) f[i] = i; for(int i = 1 ; i <= m ; i ++) { int u = read() , v = read() , w = read(); add(u,v,w); } long long Ans = 0; sort(edge + 1 , edge + 1 + cnt, cmp); for(int i = 1 ; i <= cnt ; i ++) { int from = edge[i].from , to = edge[i].to; if(find(from) != find(to)) { f[find(from)] = find(to); Ans += edge[i].w; } } cout << Ans * 2; return 0; }
T3
我怎么这么菜啊,这道题卡了比较久。。。。但是实际上并不难。
首先考虑,把长度限制按照从小答案排序后,前面的名字无论如何都会对后面的名字产生影响,也就是后面的名字不能与前面的相同。
不妨假装生成一个总的名字集合,不难发现,为了保证名字不重复,前面的名字如果出现了一次的话,后面的就不能再次出现这个名字,于是我们就把这个名字从这个集合里面“删去”,其实也并不是“删去”,而是说我们“假装”把它删去,后面计算答案的时候,都减去这个的贡献就行了。
// Problem: 照看小猫 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/11038/C // Memory Limit: 524288 MB // Time Limit: 2000 ms // Powered by CP Editor (https://github.com/cpeditor/cpeditor) #include <bits/stdc++.h> using namespace std; #define int long long const int Mod = 77797,MAXN = 1e4 + 50; int A[MAXN],M[20] = {1},book[15]; int Q[11][MAXN]; int n,sum[20]; int quickpower(int x,int k) { int ans = 1 , op = x; while(k) { if(k & 1ll) ans *= op; op = op * op; k >>= 1ll; } return ans; } signed main() { cin >> n; for(int i = 1 ; i <= n ; i ++) cin >> A[i]; for(int i = 1 ; i <= 10 ; i ++) M[i] = M[i - 1] * 26 % Mod; for(int i = 2 ; i <= 10 ; i ++) M[i] = M[i - 1] + M[i] , M[i] %= Mod; sort(A + 1 , A + 1 + n); int Ans = 1; for(int i = 1 ; i <= n ; i ++) { if(A[i] < 3 && M[A[i]] - i < 0) {cout << -1 ; return 0;} // 这里要注意,判断A[i] < 3 是因为如果 A[i] >= 3 的时候,M[A[i]] 就已经大于10000了,可能因为取模的缘故使得M[A[i]] < 10000。 else Ans = (Ans * (M[A[i]] - (i - 1))) % Mod; } cout << Ans; return 0; }