1.冶炼金属(二分、数学)
#include
using namespace std;
int get1(int a, int b){
int l = 0, r = 1e9;
while(l + 1 < r){
int mid = (l + r) / 2;
if(a / mid <= b) r = mid;
else l = mid;
}
return r;
}
int get2(int a, int b){
int l = 0, r = 1e9;
while(l + 1 < r){
int mid = (l + r) / 2;
if(a / mid < b) r = mid;
else l = mid;
}
return l;
}
int main() {
int n;
scanf("%d", &n);
int a, b;
int res1 = -1e9, res2 = 1e9;
for (int i = 0; i < n; i++) {
scanf("%d%d", &a, &b);
res1 = max(res1, get1(a, b));
res2 = min(res2, get2(a, b));
}
printf("%d %d", res1, res2);
return 0;
}
#include
using namespace std;
int main() {
int n;
scanf("%d", &n);
int a, b;
int res1 = -1e9, res2 = 1e9;
for (int i = 0; i < n; i++) {
scanf("%d%d", &a, &b);
res1 = max(res1, a / (b + 1) + 1);
res2 = min(res2, a / b);
}
printf("%d %d", res1, res2);
return 0;
}
2.飞机降落(dfs排列、状态压缩dp)
#include
#include
using namespace std;
const int N = 15;
struct node{
int a, b, c;
}p[N];
int t, n, st[N];
int dfs(int u, int beg){
if(u > n) return 1;
for(int i = 1; i <= n; i++){
int a = p[i].a, b = p[i].b, c = p[i].c;
if(!st[i] && a + b >= beg){
st[i] = 1;
if(dfs(u + 1, max(beg, a)+ c)) return 1;
st[i] = 0;
}
}
return 0;
}
int main(){
scanf("%d", &t);
while(t--){
memset(st, 0, sizeof(st));
scanf("%d", &n);
int a, b, c;
for(int i = 1; i <= n; i++){
scanf("%d%d%d", &a, &b, &c);
p[i] = {a, b, c};
}
if(dfs(1, 0)) printf("YES\n");
else printf("NO\n");
}
return 0;
}
#include
#include
using namespace std;
const int N = 20;
struct node{
int a, b, c;
}p[N];
int t, n;
int f[1 << N];
int main(){
scanf("%d", &t);
while(t--){
scanf("%d", &n);
int a, b, c;
for(int i = 0; i < n; i++){
scanf("%d%d%d", &a, &b, &c);
p[i] = {a, b, c};
}
memset(f, 0x3f, sizeof(f));
f[0] = 0;
for(int i = 1; i < 1 << n; i++){
for(int j = 0; j < n; j++){
int a = p[j].a, b = p[j].b, c = p[j].c;
if(i >> j & 1){
int st = f[i - (1 << j)];
if(a + b >= st) f[i] = min(f[i], max(st, a) + c);
}
}
}
if(f[(1 << n) - 1] == 0x3f3f3f3f) printf("NO\n");
else printf("YES\n");
}
return 0;
}
3.接龙数(最长上升子序列dp)
#include
using namespace std;
const int N = 1e5 + 10;
int n, a[N];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
int res = 0;
for(int i = 1; i < n; i++){
int x = a[i] % 10;
for(int j = i + 1; j <= n; j++){
int t = a[j], y;
while(t){
y = t % 10;
t /= 10;
}
if(x != y){
res++;
}else{
i = j - 1;
break;
}
}
}
printf("%d", res);
return 0;
}
#include
using namespace std;
const int N = 1e5 + 10;
int n, l[N], r[N];
int f[N];
int main()
{
scanf("%d", &n);
string s;
for(int i = 1; i <= n; i++){
cin>>s;
l[i] = s[0] - '0';
r[i] = s[s.size() - 1] - '0';
}
int res = 0;
for(int i = 1; i <= n; i++){
f[i] = 1;
for(int j = 1; j < i; j++){
if(l[i] == r[j]) f[i] = max(f[i], f[j] + 1);
}
res = max(f[i], res);
}
printf("%d", n - res);
return 0;
}
#include
using namespace std;
const int N = 1e5 + 10;
int n, l[N], r[N];
int f[N], g[10];
int main()
{
scanf("%d", &n);
string s;
for(int i = 1; i <= n; i++){
cin>>s;
l[i] = s[0] - '0';
r[i] = s[s.size() - 1] - '0';
}
int res = 0;
for(int i = 1; i <= n; i++){
f[i] = 1;
f[i] = max(f[i], g[l[i]] + 1);
g[r[i]] = max(g[r[i]], f[i]);
res = max(f[i], res);
}
printf("%d", n - res);
return 0;
}
要求使得数列变成接龙数列的最少删除个数, 相当于求该数列的最长接龙子数列的长度, 用总长度减去最长接龙长度即为最少删除个数。
定义dp[i][j]为前i个数中, 以数字j结尾的最长接龙数列的长度。
设第i个数的首位数字是a, 末位数字是b。 则dp[i]中相对于dp[i-1]可能发生变化的只有dp[i][b], 因为第i个数只可能加到一个以a结尾的接龙数列中, 使得这个接龙数列长度加1并且结尾数字变成b.
所以状态转移方程为dp[i][b] = max(dp[i - 1][b], dp[i - 1][a] + 1)
而显然第一维可以优化掉。
#include
using namespace std;
int f[10];
int main()
{
int n, res = 0;
scanf("%d", &n);
string s;
for(int i = 1; i <= n; i++){
cin>>s;
int l = s[0] - '0', r = s[s.size() - 1] - '0';
f[r] = max(f[r], f[l] + 1);
res = max(res, f[r]);
}
printf("%d", n - res);
return 0;
}
4.岛屿个数(dfs、bfs)
#include
using namespace std;
const int N = 55;
char g[N][N];
int n, m;
int dx[] = {0, 0, -1, 1, 1, 1, -1, -1};
int dy[] = {1, -1, 0, 0, 1, -1, 1, -1};
void dfs1(int x, int y){
g[x][y] = '2';
for(int i = 0; i < 8; i++){
int a = x + dx[i], b = y + dy[i];
if(a < 0 || a > n + 1 || b < 0 || b > m + 1 || g[a][b] != '0') continue;
dfs1(a, b);
}
}
void dfs2(int x, int y){
g[x][y] = '2';
for(int i = 0; i < 4; i++){
int a = x + dx[i], b = y + dy[i];
if(a < 1 || a > n || b < 1 || b > m || g[a][b] == '2') continue;
dfs2(a, b);
}
}
int main(){
int t;
cin>>t;
while(t--){
int res = 0;
cin>>n>>m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin>>g[i][j];
for(int i = 0; i <= n + 1; i++) g[i][0] = g[i][m + 1] = '0';
for(int j = 0; j <= m + 1; j++) g[0][j] = g[n + 1][j] = '0';
dfs1(0, 0);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
if(g[i][j] == '1'){
res++;
dfs2(i, j);
}
cout<<res<<endl;
}
return 0;
}
5.子串简写(逆序对、双指针)
#include
using namespace std;
long long res, ans;
int main()
{
int k;
string s;
char c1, c2;
cin>>k>>s>>c1>>c2;
for(int i = 0, j = k - 1; j < s.size(); i++, j++){
if(s[i] == c1) res++;
if(s[j] == c2) ans += res;
}
cout<<ans;
return 0;
}
6.整数删除(优先队列、双链表)
#include
#include
using namespace std;
#define int long long
const int N = 5e5 + 10;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
int l[N], r[N];
int st[N];
int n, k, x;
signed main(){
cin >> n >> k;
for(int i = 0; i < n; i++){
cin >> x;
st[i] = x;
q.push(make_pair(x, i));
l[i] = i - 1;
r[i] = i + 1;
if(r[i] == n) r[i] = -1;
}
while(k){
pair<int, int> it = q.top();
q.pop();
if(it.first != st[it.second]){
q.push(make_pair(st[it.second], it.second));
continue;
}
k--;
int pos = it.second, x = it.first;
if(l[pos] >= 0) st[l[pos]] += x;
if(r[pos] >= 0) st[r[pos]] += x;
if(l[pos] >= 0) r[l[pos]] = r[pos];
if(r[pos] >= 0) l[r[pos]] = l[pos];
st[pos] = -1;
}
for(int i = 0; i < n; i++){
if(st[i] != -1) cout << st[i] << " ";
}
cout << endl;
return 0;
}