程设2023期末
A.围栏
#include <iostream>
using namespace std;
int main(){
long long n, ans = 0;cin>>n;
for(long long i = 1; i <= n; ++i){
if (n % i) break;
long long tmp = n % i;
if (tmp < i) break;
ans = max(ans, (i + tmp) * 2);
}cout<<ans<<endl;
return 0;
}
B.解密
#include <iostream>
#include <cstdio>
using namespace std;
string solve(string a){
int len = a.length();
int mid = (len + 1) / 2;
if (len <= 2) return a;
string str1(a, 1, mid - 1), str2(a, mid, len - mid), str3(a, 0, 1);
return solve(str1) + str3 + solve(str2);
}
int main(){
string a;cin>>a;
cout<<solve(a)<<endl;
return 0;
}
String语法
直接把string作为参数在函数中传递,看似浪费时间,实际上复杂度也是\(O(nlogn)\)
C.传送法术
#include <iostream>
#include <cstdio>
using namespace std;
const int inf = 1000000000;
int n;string a;
int f[2000];
int main(){
cin>>n>>a;int s, t;
for (int i = 0; i < n; ++i){
f[i] = inf;
if (a[i] == 'S') s = i;
if (a[i] == 'T') t = i;
}f[s] = 0;
for (int j = 0; j < n; ++j){
for(int i = 0; i < n; ++i){
if (a[i] == '#') continue;
if (i != 0) f[i] = min(f[i], f[i - 1] + 1);
if (i != n) f[i] = min(f[i], f[i + 1] + 1);
f[i] = min(f[i], f[n - i - 1] + 1);
}
}
if(f[t] == inf) cout<<-1;
else cout<<f[t];
return 0;
}
用floyd的思想,最多进行n次松弛操作,复杂度\(O(n^2)\)
D.购买优惠券
二分答案,不知道为什么边界总是调不好
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
int a[200000];
int n, m, sum = 0;
bool solve(int x){
int cnt = 0, now = 0;
for (int i = 1; i <= n; ++i){
if (a[i] > x) return false;
if (now + a[i] > x) {cnt++; now = 0;}
now += a[i];
if (cnt > m) return false;
}
if (cnt == m && now > 0) return false;
return true;
}
signed main(){
cin>>n>>m;
for (int i = 1; i <= n; ++i) {
cin>>a[i];sum += a[i];
}
int l = (n + m - 1) / m, r = sum + 1;
while (l < r){
int mid = (l + r) / 2;
if (solve(mid)) r = mid;
else l = mid + 1;
}
cout<<l<<endl;
return 0;
}
E.建筑修建
经典贪心
#include<iostream>
#include<algorithm>
using namespace std;
int n, m, x[2000], y[2000];
struct building{
int l,r;
}a[2000];
bool cmp(building x, building y) {return x.r < y.r;}
int main() {
cin>>n>>m;
for (int i = 1; i <= n; ++i){
cin>>x[i]>>y[i];
a[i].l = x[i]; a[i].r = x[i] + y[i] - 1;
}
sort(a + 1, a + n + 1, cmp);
int now = -1, ans = 0;
for (int i = 1; i <= n; ++i){
if (a[i].l > now && a[i].r < m){
++ans;now = a[i].r;
}
}
cout<<ans<<endl;
return 0;
}
F.预测赢家
#include <iostream>
#include <vector>
using namespace std;
vector<int> a;
int solve(int l, int r){
if (r == l) return a[l];
if (r - l == 1) return max(a[l], a[r]) - min(a[l], a[r]);
return max(min(solve(l + 2, r) + a[l] - a[l + 1], solve(l + 1, r - 1) + a[l] - a[r]),
min(solve(l, r - 2) + a[r] - a[r - 1], solve(l + 1, r - 1) + a[r] - a[l]));
}
int main(){
int T;cin>>T;while (T--){
int m;cin>>m;a.clear();
for (int i = 1; i <= m; ++i) {
int x;cin>>x;a.push_back(x);
}
if (solve(0, m - 1) >= 0) cout<<"true"<<endl;
else cout<<"false"<<endl;
}
return 0;
}
读题!!!又吃了没读懂题就开始写代码的亏,think twice code once
G.海拔
最小生成树(并查集)。
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
int n, m, h[500][500];
struct edge{
pair<int, int> s, t;
int len;
bool operator < (const edge& temp)const{
return len < temp.len;
}
}a[200000];int cnt;
map<pair<int, int>, pair<int, int> > fa;
void add(int sx, int sy, int tx, int ty, int len){
a[++cnt].len = len;
a[cnt].s = make_pair(sx, sy);
a[cnt].t = make_pair(tx, ty);
fa[a[cnt].s] = a[cnt].s;fa[a[cnt].t] = a[cnt].t;
}
auto fnd(auto x){
if (fa[x] == x) return x;
else return fa[x] = fnd(fa[x]);
}
int main(){
cin>>n>>m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j){
cin>>h[i][j];
if (i > 1) add(i, j, i - 1, j, abs(h[i][j] - h[i - 1][j]));
if (j > 1) add(i, j, i, j - 1, abs(h[i][j] - h[i][j - 1]));
}
sort(a + 1, a + cnt + 1);
pair<int, int> S = make_pair(1, 1), T = make_pair(n, m);
for (int i = 1; i <= cnt; ++i){
auto s = a[i].s, t = a[i].t;
if (fnd(s) != fnd(t))
fa[fnd(s)] = fnd(t);
if (fnd(S) == fnd(T))
{cout<<a[i].len<<endl;return 0;}
}
return 0;
}
I.取数游戏
爆搜
#include <iostream>
#include <vector>
using namespace std;
struct lecture{
int k, v;
vector<int> c;
}a[200];
int n, ans;
int vis[20];
bool f(int now){
for (int i = 0; i < a[now].c.size(); ++i){
if (vis[a[now].c[i]]) return 0;
}return 1;
}
void dfs(int now, int nowv){
if (now > n) return;
if (f(now)){
for (int i = 0; i < a[now].c.size(); ++i){
vis[a[now].c[i]] = 1;
}
ans = max(ans, nowv + a[now].v);
dfs(now + 1, nowv + a[now].v);
for (int i = 0; i < a[now].c.size(); ++i){
vis[a[now].c[i]] = 0;
}
}
dfs(now + 1, nowv);
}
int main(){
cin>>n;
for (int i = 1; i <= n; ++i){
cin>>a[i].k>>a[i].v;
for (int j = 0; j < a[i].k; ++j){
int x;cin>>x;a[i].c.push_back(x);
}
}
dfs(1, 0);
cout<<ans<<endl;
return 0;
}
H.课程安排
仍然是爆搜
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n, m, a[10][10], ans;
int vis[10][10];
int fx[9] = {0, 0, 0, 1, 1, 1, -1, -1, -1};
int fy[9] = {0, 1, -1, 0, 1, -1, 0, 1, -1};
bool f(int x, int y){
for(int i = 0; i < 9; ++i)
if(vis[x + fx[i]][y + fy[i]])
return 0;
return 1;
}
void dfs(int x, int y, int now){
if (x == n && y == m) return;
if (f(x, y)){
vis[x][y] = 1;
ans = max(ans, now + a[x][y]);
dfs(y == m ? x + 1 : x, y == m ? 1 : y + 1, now + a[x][y]);
vis[x][y] = 0;
}
dfs(y == m ? x + 1 : x, y == m ? 1 : y + 1, now);
}
int main(){
int T;cin>>T;while (T--){
cin>>n>>m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cin>>a[i][j];
dfs(1, 1, 0);
cout<<ans<<endl;
ans = 0;
}
}
J.分配工作
搜索剪枝,这种分组类型的搜索还不熟练。
剪枝应该是叫IDA*的思想(?),就是剪掉大于阈值的部分
#include <iostream>
#include <cstdio>
using namespace std;
const int inf = 1000000000;
int ans = inf, cnt;
int t[20], vis[20];
void dfs(int n, int k, int now, int nowmax){
if (n == 0 && k == 0){
ans = min(ans, nowmax);
return;
}
for (int i = 1; i < cnt; ++i){
if (vis[i]) continue;
vis[i] = 1;
if (now + t[i] > nowmax && k != 0){
dfs(n - 1, k - 1, t[i], max(nowmax, t[i]));
}
if (n - 1 >= k && now + t[i] < ans){
dfs(n - 1, k, now + t[i], max(nowmax, now + t[i]));
}
vis[i] = 0;
}
}
int main(){
int k;cin>>cnt>>k;
for (int i = 0; i < cnt; ++i) cin>>t[i];
dfs(cnt - 1, k - 1, t[0], t[0]);
cout<<ans<<endl;
return 0;
}
K.蛇入迷宫
#include <iostream>
#include <vector>
using namespace std;
int n, a[200][200], vis[200][200], ans = 1000000000;
void dfs(int x, int y, int to, int now){
if(x == n - 1 && y == n - 1 && to == 1){
ans = min(ans, now);return;
}
vis[x][y] = 1;
if (to == 1){
if (y + 1 < n && a[x][y + 1] == 0 && vis[x][y + 1] == 0){
dfs(x, y + 1, 1, now + 1);
}
if (x + 1 < n && a[x + 1][y] == 0 && a[x + 1][y - 1] == 0 && vis[x + 1][y - 1] == 0){
dfs(x + 1, y, 1, now + 1);
dfs(x + 1, y - 1, 0, now + 1);
}
}
else{
if (x + 1 < n && a[x + 1][y] == 0 && vis[x + 1][y] == 0){
dfs(x + 1, y, 0, now + 1);
}
if (y + 1 < n && a[x][y + 1] == 0 && a[x - 1][y + 1] == 0 && vis[x - 1][y + 1] == 0){
dfs(x, y + 1, 0, now + 1);
dfs(x - 1, y + 1, 1, now + 1);
}
}
vis[x][y] = 0;
}
int main(){
cin>>n;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
cin>>a[i][j];
if (a[n - 1][n - 1] || a[n - 1][n - 2]) {cout<<-1<<endl;return 0;}
dfs(0, 1, 1, 0);//pos of head is (0, 1), its body is level
if (ans != 1000000000) cout<<ans<<endl;
else cout<<-1<<endl;
return 0;
}
L.最长奇异子序列
因为我们更新状态的时候只会考虑上一个数而不会考虑之前的数,所以设 f[i][j] 表示前i个数形成的最长奇异子序列且最后一个数的第 j 位是 1 。那么 f[i][j] = max{f[i - 1][k]} + a[i][j], k 是 a[i] 为 1 的数位。
滚动数组优化到一维。(lyt实在太强了
#include <iostream>
#include <cstdio>
using namespace std;
int a[200000], f[100000];
int g(int x){
int ret = 0;
for (int j = 1; j <= 32; ++j){
if (x % 2) ret = max(ret, f[j]);
}return ret + 1;
}
int main(){
int T;cin>>T;while (T--){
int n, ans = 0;cin>>n;
for (int i = 1; i <= n; ++i){
cin>>a[i];
int num = g(a[i]);
for (int j = 1; j <= 32; ++j){
if (a[i] % 2) f[j] = num;
a[i] /= 2;
ans = max(ans, f[j]);
}
}
cout<<ans<<endl;
}return 0;
}