杭电多校(四)2019.7.31--暑假集训
【HDU 6014】
SOLVED
【题目大意】给定N个节点,两点之间距离是节点编号的与,在这样的前提下,求最小生成树,输出代价和路径
【思路】通过lowbit求第一个0的位置,然后令此位为1的值就是最优解
【总结】1.与或非都要先考虑拆分后二进制的特性
2.检验算法正确性时,验证数据要是自己验证能力的最大值
(就是多验)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<string> #include<cstring> #include<climits> #include<cmath> #include<map> #include<set> #include<deque> using namespace std; const int maxn = 2e5 + 10; int arr[maxn]; int lowbit(int x) { return x & -x; } int main() { ios_base::sync_with_stdio(false); int T; cin >> T; while (T--) { int N; cin >> N; int cal = 0; for (int i = 2; i <= N; i++) { if ((i & 1) == 0) arr[i] = 1; else { int t =lowbit((i + lowbit(i))); if (t <= N) arr[i] = t; else { arr[i] = 1; cal++; } } } cout << cal << "\n"; for (int i = 2; i <= N; i++) { cout << arr[i]; if (i != N) cout << ' '; } cout << "\n"; } }
【HDU 6015】
UNSOLVED
【HDU 6016】
SOLVED
【题目大意】给数字N,要求将数字1~N分成k堆,每一堆的总和都相等,如果能则输出“yes”,并输出方案,如果不行输出“no”
【解题思路】
分类讨论
一种是n/k是偶数的,直接取头取尾然后分配就行,
一种是奇数,取前3k个,然后对后面剩余的取头取尾分配
(此处应有取前3k个可行的证明)
然后就是几个特判(程序要优美就不应该有特判)
当k==1时,输出全部
当1~N的总和不能整除k时,输出no
当k==n时输出no
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<vector> #define ll long long using namespace std; const int MAXN = 100010; vector<int> ans[MAXN]; ll n, k; void solve() { if ((n*(n + 1) / 2) % k != 0 || (k == n&&k!=1)) { printf("no\n"); return; } ll d = n / k; printf("yes\n"); if (k == 1) { for (int i = 1; i <= n; i++) { printf("%d", i); if (i != n) printf(" "); else printf("\n"); } return; } if (d & 1) { ll sum =( (1 + 3*k)*3 / 2); //printf("sum == %lld \n", sum); for (int i = 1; i <= k; i++) { ans[i].push_back(i); } int tot = k + 1; for (int i = k; i > 0; i -= 2) { ans[i].push_back(tot), tot++; } for (int i = k - 1; i > 0; i -= 2) { ans[i].push_back(tot), tot++; } for (int i = 1; i <= k; i++) { ans[i].push_back(sum - ans[i][0] - ans[i][1]); } tot = 1; ll d = ((n-3*k) / k)/2; for (int i = 1; i <= k; i++) { for (int j = 1; j <= d; j++) ans[i].push_back(3 * k + tot),ans[i].push_back(n + 1 - tot),tot++; } for (int i = 1; i <= k; i++) { for (int j = 0; j < ans[i].size(); j++) { printf("%d", ans[i][j]); if (j == ans[i].size() - 1) printf("\n"); else printf(" "); } } for (int i = 1; i <= k; i++) ans[i].clear(); } else { int cnt = 1; for (int i = 1; i <= k; i++) { for (int j = 0; j <d/2; j++) { printf("%d %d", cnt, n + 1 - cnt); if( j == (d / 2) - 1 ) printf("\n"); else printf(" "); cnt++; } } } return; } int main() { int T; scanf("%d", &T); while (T--) { scanf("%lld%lld", &n,&k); solve(); } return 0; }
【HDU 6017】
UNSOLVED
【HDU 6018】
UNSOLVED
【HDU 6019】
UNSOLVED
【HDU 6020】
SOLVED
【题目大意】给一个4*4的数字谜题,能否恢复到指定形状
【思路】数字谜题的结论
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<string> #include<cstring> #include<climits> #include<cmath> #include<map> #include<set> #include<deque> #include<unordered_map> using namespace std; struct node { int arr[5][5]; bool operator<(const node& a)const { for (int i = 1; i <= 4; i++) { for (int j = 1; j <= 4; j++) { if (arr[i][j] >= a.arr[i][j]) return false; } } return true; } node() {}; node(const int a[][5]) { for (int i = 1; i <= 5; i++) { for (int j = 1; j <= 5; j++) { arr[i][j] = a[i][j]; } } } }; map<node, int>mp; int arr[16]; const int mx[4] = { 0,-1,0,1 }; const int my[4] = { 1,0,-1,0 }; int main() { ios_base::sync_with_stdio(false); int T; cin >> T; while (T--) { int cal = 0; int px; for (int i = 1; i <= 16; i++) { int n; cin >> n; if (n == 0) { px = (i - 1) / 4 + 1; continue; } arr[++cal] = n; } int cnt = 0; for (int i = 1; i <= 15; i++) { for (int j = i + 1; j <= 15; j++) { if (arr[i] > arr[j]) cnt++; } } if ((cnt + 4 - px) % 2 == 0) cout << "Yes\n"; else cout << "No\n"; } }
【HDU 6021】
UNSOLVED
【HDU 6022】
UNSOLVED
【HDU 6023】
SOLVED
【题目大意】
【思路】对素数进行特殊处理,先求N^1/5,于是剩下的素数的幂次最高只能是4了,可以二分开根迅速求解
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<algorithm> #define ll long long using namespace std; ll pri[10001]; int vis[10001]; int cntp; void init() { for (ll i = 2; i < 10000; i++) { if (!vis[i]) { cntp++; pri[cntp] = i; } for (int j = 1; j <= cntp&&pri[j]*i<10000; j++) { vis[i*pri[j]] = 1; if (i%pri[j] == 0) { break; } } } } ll sqrt(ll num,int d) { ll l = 1, r = num; while (l <= r) { ll mid = (l+r) / 2; ll tmp = LLONG_MAX; if(d==3) { tmp = tmp / mid; } if (d == 4) { tmp = tmp / mid; tmp /= mid; } if (tmp / mid < mid) { r = mid - 1; continue; } tmp = 1; for (int i = 1; i <= d; i++) tmp *= mid; if (tmp == num) return mid; if (tmp > num) r = mid - 1; else l = mid + 1; } return 0; } int main() { init(); int T; scanf("%d", &T); while (T--) { ll n; scanf("%lld", &n); int ans = INT_MAX; for (int i = 1; i <= cntp; i++) { if (pri[i] > n) break; int cnt = 0; while (n%pri[i] == 0) { cnt++; n/= pri[i]; } //if (cnt) // printf("cnt %d pri %lld\n", cnt, pri[i]); if (cnt < ans && cnt) ans = cnt; } int res = INT_MAX; if (n>1) { if (sqrt(n, 4)) res = min(res, 4); else { if (sqrt(n, 2)) res = min(res, 2); } if (sqrt(n, 3)) res = min(res, 3); if (res == INT_MAX && n > 4500) res = 1; } printf("%d\n", min(ans,res)); } //printf("1000000000000000000 %lld %lld\n", sqrt(1000000000000000000, 3), sqrt(1000000000000000000, 2)); return 0; }