A: 算法竞赛
解题思路:
签到题,就不说了。
解题代码:
#define int long long
const int N = 1e6+5;
int arr[N];
void solve() {
int n,m; cin >> n;
int len = 0; cin >> len;
for(int i = 1; i<= len; i++)
cin >> arr[i];
cin >> m;
int ans = 0, l = 1;
for(int i = n; i <= m; i++){
if(arr[l] == i && l <= len){
l ++;
continue;
}
ans ++;
}
cout << ans << endl;
}
B: 基站建设
解题思路:
该题是一道动态规划(dp)的题,还需要进行滑动窗口的优化才能过。
该题的主要思路如下:
- 先对这个进行线段进行处理,由于需要对任意两个线段之间安装站点,那么可以进行预处理,将右端的点指向左端点。
- 然后进行dp的操作,因为只需要对当前区间的上一个需要安装站点的区间进行操作,如果不在上一个节点之内的值全进行pop掉,然后取上一个区间的最小值。
- 因为要取区间的最小值,可以用优先队列(滑动窗口)算法进行操作,就可以进行得到需要的值。
解题代码:
const int N = 1e6 + 6;
array<int,N> arr;
int dp[N]; // dp值
int pre[N]; //
void solve(){
int n,m; cin >> n;
for(int i = 1; i<= n; i++){
cin >> arr[i];
dp[i] = 1e18; // 初始化
}
for(int i =1 ; i <= n + 1; i++) pre[i] = 0; // 初始化
cin >> m;
for(int i= 1; i <= m; i++){
int a, b ; cin >> a >> b;
pre[b + 1] = max(pre[b + 1], a); // 进行线段的处理
}
priority_queue<PII,vector<PII>, greater<PII> > pq; // 定义小根堆
pq.push({0,0});
for(int i = 1; i <= n; i++){
// 滑动窗口
while(pq.size() && pq.top().se < pre[i]) pq.pop();
dp[i] = pq.top().fi + arr[i]; // dp操作
pq.push({dp[i],i});
}
while(pq.size() && pre[n + 1] > pq.top().se) pq.pop(); // 为了使最后的得到的值在在最后一个区间,比如如果最后一段的右节点为n,那么就没法保证区间在最后一段
cout << pq.top().fi << endl;
return ;
}
C: 市场交易
思路:
该题就是双指针,注意数据范围。
代码:
#define PII pair<int,int>
#define int long long
using namespace std;
const int N = 1e6+5;
PII arr[N];
void solve() {
int n,m;
cin >> n;
for(int i = 1; i<= n; i++)
cin >> arr[i].fi >> arr[i].se;
sort(arr + 1,arr + 1+ n);
int l = 1, r = n;
int ans = 0;
while(r > l){
int maxx = min(arr[l].se, arr[r].se);
int res = maxx * (arr[r].fi - arr[l].fi);
ans += res;
arr[l].se -= maxx, arr[r].se -= maxx;
if(arr[l].se == 0) l ++;
if(arr[r].se == 0) r --;
}
cout << ans << endl;
}
D: 新居规划
思路:
该题运用前缀和和遍历的思想进行实现的。
首先先对其排个序(排序方式就是求 a i − b i a_i - b_i ai−bi,大的排前面,小的排后面), 因为会有两段,一段是有领居的,一段是没有领居的。因为有领居和没有领居只能取一边,那么就形成的这样的一个构造:
那么就只需要进行枚举就行了,枚举没有领居的个数,然后判断该没有领居的个数是否合法。如果合法的话,就进行计算这样形成的情况得到的满意度的总值,然后再进行比较哪个总值最大。
注意:当有领居的个数为1和0得到的值都是一样的,这个需要进行特判。
代码:
#define int long long
const int N = 1e6+5;
PII arr[N];
bool cmp(PII a, PII b){
return a.fi - a.se > b.fi - b.se;
}
int suma[N],sumb[N];
void solve() {
int n,m;
cin >> n >> m;
for(int i = 1; i<= n; i++){
cin >> arr[i].fi >> arr[i].se;
suma[i] = 0;
sumb[i] = 0;
}
sort(arr + 1, arr + 1+ n, cmp);
for(int i= 1; i <= n; i++){
suma[i] = suma[i - 1] + arr[i].fi;
sumb[i] = sumb[i - 1] + arr[i].se;
}
int ans = 0;
for(int i = 0; i <= n; i++){
int j = m - 2 * i;
if(j < n - i) {
break;
}
int res = 0;
if(i >= n - 1) res = sumb[n];
else res = suma[n - i] + sumb[n] - sumb[n - i];
ans = max(ans,res);
}
cout << ans << endl;
}
I: 路径规划
解题思路:
该题的主要思路是二分。二分答案,这个主要找到先后关系,就比如在同一条线上,他们的位置大小顺序肯定都是依次递增的,那么我们就可以进行二分答案。该题主要就是check函数,如果直接在check函数中排序,那么时间会在第6个样例超时,那么就需要进行优化。
既然不能在check函数中进行排序,那么就在main函数中进行排序,然后在check函数中进行遍历的时候,因为坐标是排好序的状态,当遍历到小于等于x的时候就进行比较与前面的那个的大小,如果出现不是递增的状态话就说明不成立。
解题代码:
bool cmp(PII a, PII b){
if(a.se.fi != b.se.fi) return a.se.fi > b.se.fi;
return a.se.se > b.se.se;
}
vector<pair<int,pair<int,int>>> temp;
bool check(int x){
int a,b,flag = 0;
for(int i= 0; i < temp.size();i++)
if(flag == 0 && temp[i].fi <= x){
flag = 1;
a = temp[i].se.fi, b = temp[i].se.se;
}
else if(temp[i].fi <= x){
if(temp[i].se.fi > a || temp[i].se.se > b)
return false;
a = temp[i].se.fi, b = temp[i].se.se;
}
return true;
}
void solve() {
int n,m;
cin >> n >> m;
temp.clear();
for(int i = 1; i<= n; i++){
for(int j = 1; j <= m; j++){
int a; cin >> a;
temp.push_back({a,{i,j}});
}
}
sort(temp.begin(),temp.end(),cmp);
int l = 1, r = n*m;
while(r > l){
int mid = l + r >> 1;
if(check(mid)) l = mid + 1;
else r = mid;
}
cout << r << endl;
}
K: 独立钻石
解题思路:
看到这个题的数据范围就是大暴搜,直接搜索每个位置就行了。
解题代码:
const int N = 10;
int arr[N][N];
int xx[] = {0,0,1,-1},yy[] = {1,-1,0,0};
int n,m,k;
int ans = 1e9;
void dfs(){
// cout << 111 << endl;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
if(arr[i][j] == 1)
for(int k = 0; k < 4; k++){
int tempx = i + xx[k], tempy = j + yy[k];
if(tempx > 0 && tempx <= n && tempy > 0 && tempy <= m && arr[tempx][tempy] == 1){
int tempxx = tempx + xx[k],tempyy = tempy + yy[k];
if(tempxx > 0 && tempxx <= n && tempyy > 0 && tempyy <= m && arr[tempxx][tempyy] == 0){
arr[tempxx][tempyy] = 1;
arr[tempx][tempy] = 0;
arr[i][j] = 0;
dfs();
arr[tempxx][tempyy] = 0;
arr[tempx][tempy] = 1;
arr[i][j] = 1;
}
}
}
int res = 0;
for(int i =1 ; i <= n; i++)
for(int j = 1; j <= m; j++)
if(arr[i][j] == 1)
res ++;
ans = min(ans,res);
}
void solve() {
cin >> n >> m >> k;
memset(arr,0,sizeof(arr));
ans = 1e9;
for(int i = 1; i<= k; i++){
int a,b; cin >> a >> b;
arr[a][b] = 1;
}
dfs();
cout << ans << endl;
}