蓝桥杯训练
递推与递归
AcWing
92. 递归实现指数型枚举
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 20;
int n;
bool vis[N];
inline int read()
{
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
void dfs( int x )
{
if( x > n )
{
for( int i = 1 ; i <= n ; i ++ )
if( vis[i] ) printf("%d " , i );
printf("\n");
return ;
}
dfs( x + 1 );
vis[x] = 1;
dfs( x+1 );
vis[x] = 0;
return ;
}
int main()
{
n = read();
dfs(1);
return 0;
}
94. 递归实现排列型枚举
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 20;
int n , num[N];
bool vis[N];
inline int read()
{
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
void dfs( int x )
{
if( x > n )
{
for( int i = 1 ; i <= n ; i ++ )
printf("%d " , num[i] );
printf("\n");
return ;
}
for( int i = 1 ; i <= n ; i ++ )
{
if( vis[i] ) continue;
vis[i] = 1;
num[x] = i;
dfs( x + 1 );
vis[i] = 0;
}
return ;
}
int main()
{
n = read();
dfs(1);
return 0;
}
717. 简单斐波那契
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 50;
int n , b[N];
inline int read()
{
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
int main()
{
n = read();
b[1] = 1;
for( int i = 2 ; i < n ; i ++ )
b[i] = b[i-1] + b[i-2];
for( int i = 0 ; i < n ; i ++ )
printf("%d " , b[i] );
printf("\n");
return 0;
}
95. 费解的开关
首先对于一个开关如果按了两次是没有意义的,其次按开关的顺序对结果也不产生影响
先枚举出第一行开关所有的方案,然后从第二行开始,如果某个位置的上一行是灭的想打开必须按当前位置,这样操作后判断一下最后一行时候全开就好
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 8;
const int dx[]={-1,0,0,0,1 },dy[]={0,1,0,-1,0};
int n = 5 , cnt , b[N][N] , c[N][N], v[N] , res ;
string s;
inline int read()
{
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
void opt( int x , int y ){
for( int i = 0 ; i <= 4 ; i ++ )
if( b[x+dx[i]][y+dy[i]] )
b[x+dx[i]][y+dy[i]] = 0;
else
b[x+dx[i]][y+dy[i]] = 1;
return ;
}
void dfs( int x )
{
if( x > n )
{
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= n ; j ++ )
b[i][j] = c[i][j];
cnt = 0;
for( int i = 1 ; i <= n ; i ++ )
if( v[i] ) opt( 1 , i ) , cnt ++;
for( int i = 2 ; i <= n ; i ++ )
for( int j = 1 ; j <= n ; j ++ )
{
if( b[i-1][j] ) continue;
opt( i , j ) , cnt ++;
}
for( int i = 1 ; i <= n ; i ++ )
if( b[n][i] == 0 ) return ;
res = min( cnt , res );
return ;
}
v[x] = 1 , dfs(x+1) , v[x] = 0;
dfs(x+1);
}
void slove()
{
for( int i = 1 ; i <= n ; i ++ )
{
cin >> s;
for( int j = 1 ; j <= n ; j ++ )
c[i][j] = (s[j-1] == '1' ) ? 1 : 0;
}
res = 7;
dfs( 1 );
if( res <= 6 )
cout << res << endl;
else
cout << "-1\n";
return ;
}
int main()
{
int t = read();
while( t -- )
slove();
return 0;
}
93. 递归实现组合型枚举
#include<bits/stdc++.h>
using namespace std;
const int N = 30;
int n , m , a[N];
void dfs( int x , int s )
{
if( x > m )
{
for( int i = 1 ; i <= m ; i ++ )
cout << a[i] << ' ';
cout << endl;
return ;
}
for( int i = s ; i <= n ; i ++ )
a[x] = i , dfs( x + 1 , i + 1 );
return ;
}
int main()
{
cin >> n >> m;
dfs( 1 , 1 );
}
1209.带分数
首先我们生成序列的全排列,然后\(n^2\)枚举一下两个分界点,分成三个数字判断一下就好
#include<bits/stdc++.h>
using namespace std;
const int N = 12;
int n , a[N] , res;
int main()
{
cin >> n;
for( int i = 1 ; i <= 9 ; i ++ )
a[i] = i;
int s , t , w ;
do{
for( int i = 1 ; i < 9 ; i ++ )
for( int j = i + 1 ; j < 9 ; j ++ )
{
s = t = w = 0;
for( int k = 1 ; k <= i ; k ++ )
s = s*10 + a[k];
for( int k = i+1 ; k <= j ; k ++ )
t = t*10 + a[k];
for( int k = j+1 ; k <= 9 ; k ++ )
w = w*10 + a[k];
if( s == 0 || t == 0 || w == 0 ) continue;
if( t % w ) continue;
if( s + t / w == n ) res ++;
}
}while(next_permutation( a + 1 , a + 10 ) );
cout << res << endl;
return 0;
}
116. 飞行员兄弟
因为数字很少,直接用枚举的方式枚举所有的情况找出符合条件的
#include<bits/stdc++.h>
using namespace std;
const int N = 5;
int n = 3 ;
char s[N][N] , backup[N][N];
vector< pair<int,int> > res;
int get( int x , int y ){
return x*4+y;
}
void turn_one( int x , int y )
{
if( s[x][y] == '+' ) s[x][y] = '-' ;
else s[x][y] = '+';
}
void turn_all( int x , int y )
{
for( int i = 0 ; i <= n ; i ++ )
turn_one( x , i ) , turn_one( i , y );
turn_one( x , y );
}
int main()
{
for( int i = 0 ; i <= 3 ; i ++ )
cin >> backup[i];
for( int op = 0 ; op < (1<<16) ; op ++ )
{
memcpy( s , backup , sizeof( backup ) );
vector<pair<int,int> > temp;
for( int i = 0 ; i <= n ; i ++ )
for( int j = 0 ; j <= n ; j ++ )
{
if( (op >> get( i , j )) & 1 )
turn_all( i , j ) , temp.push_back({i,j}) ;
}
bool f = 1;
for( int i = 0 ; i <= n ; i ++ )
for( int j = 0 ; j <= n ; j ++ )
if( s[i][j] == '+' ) f = 0;
if( f && ( res.empty() || res.size() > temp.size() ) )
res = temp;
}
cout << res.size() << endl;
for( auto [x,y] : res )
cout << x+1 << ' ' << y+1 << endl;
return 0;
}
1208. 翻硬币
因为题目一定有解, 贪心的做一下就好了
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int n , v[N];
string a , b;
int main()
{
cin >> a >> b;
n = a.size();
for( int i = 1 ; i <= n ; i ++ )
v[i] = a[i-1] == b[i-1];
int cnt = 0;
for( int i = 1 ; i < n ; i ++ )
if( v[i] == 0 )
v[i] = 1 , v[i+1] ^= 1 , cnt ++;
cout << cnt << endl;
return 0;
}
二分和前缀和
Acwing
789. 数的范围
正常可以二分查找起点和终点但是因为数据范围很小直接用数组统计端点即可
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e4+5;
int n , l[N] , r[N] , q ;
inline int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x ;
}
int main(){
n = read() , q = read();
for( int i = 1 ; i <= 10000 ; i ++ )
l[i] = r[i] = -1;
for( int i = 0 , x ; i < n ; i ++ )
{
x = read(),r[x] = i;
if( l[x] == -1 ) l[x] = i;
}
for( int x ; q ; q -- )
x = read() , printf("%d %d\n" , l[x] , r[x] );
return 0;
}
790. 数的三次方根
直接运算的都话很困难,但是因为范围有限,可以直接把答案二分出来
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
double x , l = -10000, r = 10000 , mid , res ;
cin >> x;
while( l <= r && ( r - l ) >= 1e-7 )
{
mid = ( l + r) / 2.0;
if( mid*mid*mid <= x ) l = mid + 1e-7;
else r = mid - 1e-7;
}
printf( "%.6lf\n" , l );
}
795. 前缀和
模板
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n , m , a[N];
int main()
{
cin >> n >> m;
for( int i = 1 ; i <= n ; i ++ ){
cin >> a[i];
a[i] += a[i-1];
}
for( int l , r ; m ; m -- )
{
cin >> l >> r;
cout << a[r] - a[l-1] << endl;
}
return 0;
}
796. 子矩阵的和
二位前缀和模版
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1005;
int n , m , q ;
ll a[N][N];
inline int read()
{
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x *f;
}
int main(){
n = read() , m = read() , q = read();
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= m ; j ++ )
a[i][j] = read() + a[i-1][j] + a[i][j-1] - a[i-1][j-1];
for( int x1 , x2 , y1 , y2 ; q ; q -- )
x1 = read()-1 , y1 = read()-1 , x2 = read() , y2 = read() , printf("%d\n" , a[x2][y2] - a[x2][y1] - a[x1][y2] + a[x1][y1] );
}
730. 机器人跳跃问题
无论是那种情况都可以得到\(E_{k+1}=2\times E_k-H_{k+1}\),这样我们发现该问题满足了二分性,可以二分答案
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5;
int n , m , q , a[N];
inline int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x ;
}
bool check( int e ){
for( int i = 1 ; i <= n ; i ++ )
{
e = 2*e-a[i];
if( e < 0 ) return 0;
if( e >= 1e5 ) return 1;
}
return 1;
}
int main(){
n = read();
for( int i = 1 ; i <= n; i ++ )
a[i] = read();
int l = 0 , r = 1e5 , mid , res ;
while( l <= r )
{
mid = ( l + r ) >> 1;
if( check(mid) ) res = mid , r = mid-1;
else l = mid+1;
}
cout << res << endl;
}
1221. 四平方和
暴力算法可以过,而且比正解更加优秀,就是单纯枚举加一些剪枝就好了
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
for( int a = 0 ; a * a * 4 <= n ; a ++ )
for( int b = a ; a * a + b * b * 3 <= n ; b ++ )
for( int c = b ; a * a + b * b + c * c * 2 <= n ; c ++ )
{
int t = n - a * a - b * b - c * c ;
int d = sqrt( t);
if( d * d == t )
printf("%d %d %d %d" , a , b , c , d ) , exit(0);
}
return 0;
}
1227. 分巧克力
二分答案,判断一下就好了
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n , k;
int r[N] , c[N];
inline int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
bool check( int x )
{
int cnt = 0;
for( int i = 1 ; i <= n && cnt < k ; i ++ )
cnt += (r[i] / x) * (c[i] / x);
return cnt >= k;
}
int main()
{
n = read() , k = read();
for( int i = 1 ; i <= n ; i ++ )
r[i] = read() , c[i] = read();
int l = 1 , r = 1e5 , mid , res;
while( l <= r )
{
mid = ( l + r ) >> 1 ;
if( check(mid) ) res = mid , l = mid + 1 ;
else r = mid-1;
}
cout << res << endl;
return 0;
}
首先想到一个暴力做法求前缀和枚举左端点二分查找右端点时候存在
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5;
int n , k , cnt;
ll a[N];
inline int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
int main()
{
n = read() , k = read();
for( int i = 1 ; i <= n ; i ++ )
a[i] = read() + a[i-1];
for( int i = 0 , t ; i <= n ; i ++ )
for( int j = 1 ; a[i] + j * k <= a[n] ; j ++ ) {
t = lower_bound(a + 1, a + 1 + n, a[i] + j * k) - a;
if (a[t] - a[i] == k * j) cnt++;
}
cout << cnt << endl;
return 0;
}
99. 激光炸弹
一道简单的二维前缀和的模板题,首先要计算出二维前缀和,然后枚举一下矩形的一个点就好了
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5005;
int n , m , a[N][N] , res ;
int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
int main()
{
n = read() , m = min( 5001 , read() );
for( int u , v ; n ; n -- )
u = read() + 1, v = read() + 1 , a[u][v] += read();
for( int i = 1 ; i <= 5001 ; i ++ )
for( int j = 1 ; j <= 5001 ; j ++ )
a[i][j] += a[i][j-1] + a[i-1][j] - a[i-1][j-1];
for( int i = m ; i <= 5001 ; i ++ )
for( int j = m ; j <= 5001 ; j ++ )
res = max( res , a[i][j] - a[i-m][j] - a[i][j-m] + a[i-m][j-m] );
cout << res << endl;
return 0;
}
1230. K倍区间
首先可以计算前缀和,然后枚举起点和终点来判断区间时候是k的倍数,但是因为如果两个数的擦取模等于零说明两个数取模的相同,所有并不用枚举两个端点,只需要看当前点之前有多少个点和当前点同余即可
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100005;
ll n , res , a[N] , cnt[N] , k;
int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
int main()
{
n = read() , k = read();
for( int i = 1 ; i <= n ; i ++ )
a[i] = (a[i-1] + read()) % k , res += cnt[ a[i] ] , cnt[ a[i] ] ++;
cout << res + cnt[0] << endl;
return 0;
}
贪心
AcWing
055. 股票买卖 II
首先(b-a) + (c-b) = c - a
所以对于一个盈利的区间可以任意拆分成多个盈利区间,所以只要今天比昨天贵就昨天买今天卖
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5;
ll n , a[N] , res;
int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
int main()
{
n = read() , a[0] = 0x7f7f7f7f;
for( int i = 1 ; i <= n ; i ++ )
{
a[i] = read();
if( a[i] > a[i-1] ) res += a[i] - a[i-1];
}
cout << res << endl;
return 0;
}
1536. 均分纸牌
如果当前点不满足就要从下一个点移过来或移向下一个点
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 105;
ll n , a[N] , ans , tot;
int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
int main()
{
n = read() ;
for( int i = 1 ; i <= n ; i ++ ) a[i] = read() , tot += a[i];
tot /= n;
for( int i = 1 ; i <= n ; i ++ )
if( a[i] != tot ) a[i+1] += a[i] - tot , ans ++;
cout << ans << endl;
return 0;
}
104. 货仓选址
把货场选在中位数
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5;
ll n , a[N] , res , t ;
int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
int main()
{
n = read() , a[0] = 0x7f7f7f7f;
for( int i = 1 ; i <= n ; i ++ ) a[i] = read();
sort( a+1 , a+1+n );
if( n & 1 ) t = a[n/2+1];
else t = (a[n/2] + a[n/2+1]) / 2;
for( int i = 1 ; i <= n ; i ++ ) res += abs( a[i] - t );
cout << res << endl;
return 0;
}
122. 糖果传递
首先令每一个人传给下一个人的糖果数为\(x_i\),答案则为\(\sum_{i=1}^{n}|x_i|\)
设糖果的平均数为\(b\) ,由题可知
令\(C_i=(i-1)b-\sum_{k=2}^{i}a_k\)另外规定\(C_1=0\),则答案就转变成了\(|x_1-C_1|+|x_1-C_2|+\cdots+|x_1-C_n|\)就转换成能了 仓库选址这道题
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+5;
ll n , a[N] , ans , tot , c[N] , mid ;
int read()
{
int x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
int main()
{
n = read() ;
for( int i = 1 ; i <= n ; i ++ ) a[i] = read() , tot += a[i];
tot /= n;
for( int i = 2 ; i <= n ; i ++ )
c[i] = c[i-1] + tot - a[i];
sort( c + 1 , c + 1 + n );
if( n & 1 ) mid = c[n/2+1];
else mid = (c[n/2] + c[n/2+1]) / 2;
for( int i = 1 ; i <= n ; i ++ )
ans += abs( mid - c[i] );
cout << ans << endl;
return 0;
}
112. 雷达设备
首先计算出每个小岛可以被雷达覆盖的区域,然后就转化成了区间覆盖的模板问题
#include<bits/stdc++.h>
using namespace std;
const int N = 1005;
int n , d , cnt ;
double f , eps = 1e-6;
pair< double , double > e[N];
int read()
{
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
int main()
{
n = read() , d = read();
double delta;
for( int i = 1 , x , y ; i <= n ; i ++ )
{
x = read() , y = read();
if( y > d )
printf("-1\n") , exit(0);
delta = sqrt( 1.0 * d * d - 1.0 * y * y );
e[i].first = x + delta , e[i].second = x - delta;
}
sort( e+1 , e+1+n );
f = - 1000000;
for( int i = 1 ; i <= n ; i ++ )
{
if( e[i].second > f + eps )
cnt ++ , f = e[i].first;
}
cout << cnt << endl;
}
1235. 付账问题
少于平均数的要付全部,大于平均数的要尽可能的少付
首先排个序,如果当前比平均值少,那么后面的平均值必然要增加
如果当前数比平均数高,则后面的都不需要多付支付平均数就好
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e5+5;
ll n , s ;
int a[N] ;
long double avg, cur_avg , sum;
ll read()
{
ll x = 0 , ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x;
}
int main()
{
n = read() , s = read();
cur_avg = avg = 1.0 * s / n;
for( int i = 1 ; i <= n ; i ++ )
a[i] = read();
sort( a+1 , a+1+n );
for( int i = 1 ; i <= n ; i ++ )
if( a[i] < cur_avg ){
s -= a[i];
sum += ( avg - a[i] ) * ( avg - a[i] );
cur_avg = 1.0 * s / ( n - i );
}
else{
sum += ( avg - cur_avg ) * ( avg - cur_avg );
}
printf("%.4Lf\n" , sqrt( sum / n ) );
return 0;
}
1239. 乘积最大
k==n
全选
k<n
分奇偶,偶数一定非负,奇数全负才是负数
选数的时候一次选两个就好
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5 , mod = 1000000009;
ll n , s , res = 1, a[N];
int main()
{
cin >> n >> s;
for( int i = 1 ; i <= n ; i ++ )
cin >> a[i];
sort( a+1 , a+1+n );
int l = 1 , r = n , sign = 1;
if( s & 1 )
{
s --;
res = a[r--];
if( res < 0 ) sign = -1;
}
while( s )
{
ll x = a[l] * a[l+1] , y = a[r] * a[r-1];
if( (x-y) * sign > 0 ){
res = x % mod * res % mod;
l += 2;
}
else {
res = y % mod * res % mod;
r -= 2;
}
s -= 2;
}
cout << res << endl;
return 0;
}
1247. 后缀表达式
首先特判M=0
的情况,直接把所有的加起来
后缀表达式有一个性质就是可以转化成中缀表达的式和括号的形式,所以可以组合成不少于一个任意多给减号,所以每一个数正数可以加负数可以减
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5+5;
ll n , m , res , a[N];
int main()
{
cin >> n >> m;
for( int i = 1 ; i <= n+m+1 ; i ++ )
cin >> a[i];
if( m == 0 )
{
for( int i = 1 ; i <= n+m+1 ; i ++ )
res += a[i];
cout << res ;
return 0;
}
sort( a+1 , a+n+m+2 );
res = a[n+m+1] - a[1];
for( int i = 2 ; i <= n+m ; i ++ )
res += abs( a[i] );
cout << res << endl;
return 0;
}
1248. 灵能传输
首先灵能传输并不会对灵能的总和产生影响,一次灵能交换可以交换相邻两个位置的前缀和,所以我们希望他最大值最小就是让他的前缀和曲线尽可能的平滑
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 300005;
ll n , a[N] , res , s[N];
bool st[N];
ll read(){
ll x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
void slove(){
n = read();
s[0] = 0;
for( int i = 1 ; i <= n ; i ++ )
a[i] = read() , s[i] = s[i-1] + a[i];
ll s0 = s[0] , sn = s[n];// 前缀和会爆 int 这里也要用 long long
if( s0 > sn ) swap( s0 , sn );
sort( s , s+1+n );
for( int i = 0 ; i <= n ; i ++ )
if( s[i] == s0 ){
s0 = i;
break;
}
for( int i = n ; i >= 0 ; i -- )
if( s[i] == sn ){
sn = i;
break;
}
memset( st , 0 , sizeof st );
int l = 0 , r = n ;
for( int i = s0 ; i >= 0 ; i -= 2 )
a[ l ++ ] = s[i] , st[i] = 1;
for( int i = sn ; i <= n ; i += 2 )
a[ r -- ] = s[i] , st[i] = 1;
for( int i = 0 ; i <= n ; i ++ )
if( !st[i] )
a[l++] = s[i];
res = 0;
for( int i = 1 ; i <= n ; i ++ )
res = max( res , abs( a[i] - a[i-1] ) );
cout << res << endl;
return ;
}
int main()
{
int t = read();
while( t-- )
slove();
return 0;
}
51nod
1508 操作队列
就是按照要求直接进行模拟
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
int main()
{
queue<int> q;
int n = read();
for( int op , x ; n ; n -- )
{
op = read();
if( op == 1 )
x = read() , q.push(x);
else
if( q.size() ) printf("%d\n" , q.front()) , q.pop();
else printf("empty\n");
}
return 0;
}
2133 排队接水
接水时间越长的人排队时间应该更短,所以接水的位次应该更加靠前
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1005;
int n , a[N] , res;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
int main()
{
n = read();
for( int i = 1 ; i <= n ; i ++ ) a[i] = read();
sort( a+1 , a+1+n);
for( int i = 1 ; i <= n ; i ++ )
a[i] += a[i-1] , res += a[i];
cout << res << endl;
return 0;
}
2070 最小罚款
这题要做的就是尽可能的少罚款,所以要优先安排罚款多的
对应相同罚款的应该尽早安排截止时间早的
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1005;
int n , m;
bool vis[N];
struct game{
int t , w;
friend bool operator < ( game a , game b ){
if( a.w != b.w ) return a.w > b.w;
else return a.t < b.t;
}
} a[N];
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
return x*f;
}
int main()
{
m = read() , n = read();
for( int i = 1 ; i <= n ; i ++ )
a[i].t = read();
for( int i = 1 ; i <= n ; i ++ )
a[i].w = read();
sort( a+1 , a+1+n );
for( int i = 1 , found ; i <= n ; i ++ )
{
found = 0;
for( int j = a[i].t ; j >= 1 && !found ; j -- )
if( !vis[j] ) vis[j] = found = 1;
if( found ) continue;
m -= a[i].w;
}
cout << m << endl;
return 0;
}
数学与简单 dp
AcWing
1205. 买不到的数目
这不就是小凯的疑惑吗?
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
int a , b;
cin >> a >> b;
cout << a * b - a - b << endl;
}