2024 ICPC复习 20-30页
https://www.luogu.com.cn/problem/CF1703G

首先这个题一定要意识到 他是一个折半的操作
1e9最多被操作30次 所以我么完全dp第二维可以放这个次数
然后 dp数组就开出来了 时间复杂度也就明确了
对于某一个箱子 可以使用好钥匙打开也可以不用 用坏钥匙
好钥匙打开就是
dp i j=dp[i-1][j]-k+a[i]>>j 坏钥匙 dp[i-1][j-1]+a[i]>>j
不过还需要思考到 如果我已经超过了30把钥匙的情况 dp[i][30]=max(dp[i-1][30]+0,dp[i][30]) 可能自己是第31把了
https://www.luogu.com.cn/problem/CF1692D

这道题还是不太会做 看到心里还是不敢想
题解写法是暴力模拟就行 反正几千分钟之内必须会回来
然后超出了一小时就% 24也是% 如果循环就break
bool check(int x, int y ) {
if (x / 10 == y % 10) {
if (x % 10 == y / 10)
return 1;
}
return 0;
}
void solve() {
int num = 0;
cin >> aa >> bb >> c >> dd >> ee;
a = aa - '0';
b = bb - '0';
d = dd - '0';
e = ee - '0';
cin >> x;
int hs = a * 10 + b;
int lte = d * 10 + e;
for (int i = 1; i <= 2406 ;i++) {
lte += x;
if (lte >= 60) {
hs += lte / 60;
lte %= 60;
}
if (hs >= 24)
hs %= 24;
if (check(hs, lte))num++;
if (hs / 10 == a && hs % 10 == b && lte / 10 == d && lte % 10 == e)break;
}
cout << num << endl;
}
https://www.luogu.com.cn/problem/CF1692H

再次做到这个题 我已经忘了怎么做了 并且 我还没想出来
题解说这个是dp思想 说实话我没感觉出来
那么这个题的具体做法就是 必须我们得知道上一个同样的数字在哪里出现了
而且我们还得知道这两个隔得数字不能使得上一个数字产生得贡献为小数去了 (如果上一个是可行的答案) 这样有的变大 我们肯定要 对吧?
所以必须多开数组来记录 其实这一步好熟悉啊 我不知道在哪里还做过
for(int i=1;i<=n;i++){
cin>>a[i];
ls[i]=ma[a[i]];
ma[a[i]]=i;
}
这是核心思想了 再来看看代码分析
for(int i=1;i<=n;i++)
{
if(f[ls[i]]-(i-ls[i]-1)>0)
{
f[i]=f[ls[i]]-(i-ls[i]-1)+1;
l[i]=l[ls[i]];//记录此时的l指向上一个同样的数字
}else {
f[i]=1;
l[i]=i;
}
if(ans<f[i])
{
ans=f[i];
flag=i;
}// 只需要通过一个flag 我们就能知道所有 非常好的一道题
}
cout<<a[flag]<<" "<<l[flag]<<" "<<flag<<endl;
https://www.luogu.com.cn/problem/CF1927D

这道题需要使用打标记的思想
我们可以开一个pair的vector 对他进行标记处理 如果不想等的话读入vector里
那么v的size就是他的标记 二维就是位置 访问起来就很轻松了
vector<pair<int, int>>v;
map<int, int>m;
int a[200005];
for (int i = 0; i < n; i++)cin >> a[i];
v.push_back({a[0], 0});
int q;
cin >> q;
for (int i = 0; i < n; i++) {
while (i < n && v.back().first == a[i]) {
m[i++] = v.size() - 1;
}
if (i != n) {
v.push_back({a[i], i});
m[i]=v.size()-1;
}
}
for (int i = 1; i <= q; i++) {
int l, r;
cin>>l>>r;
l--;r--;
if (m[l] == m[r])cout << "-1 -1" << endl;
else cout<<l+1<<" "<<v[m[l]+1].second+1<<endl;
}
https://www.luogu.com.cn/problem/CF1918C

再次思考感觉也就那样这题 不过要注意一个点 倒着从60开始
然后 我们注意要 知道第一差值 后面都是去弥补他
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve() {
ll a, b, r;
ll now = 0;
cin >> a >> b >> r;
bool high = 0;
// i也要 ll
//1LL 1ll都一样
for (ll i = 60; i >= 0; i--) {
bool x = (a & (1ll << i));//不加bool 那么返回的将是一个二进制数
//这样就完蛋了
bool y = (b & (1ll << i));
if (x == y)continue;
if (high == 0) {
now = (x - y) * (1ll << i);
high = 1;
// cout<<x<<" "<<y<<" "<<(1ll << i)<<endl;
// cout<<now<<" "<<i<<endl;
} else {
if ((x - y)*now > 0 && (1ll << i) <= r) {
// cout<<now<<" "<<(1ll << i) * (x - y)<<" "<<i<<endl;
now = now - (1ll << i) * (x - y);
r = r - (1ll << i);
//漏了 r的更新 因为贪心 r的改变要用在刀刃上
} else {
// cout<<now<<" "<<(1ll << i) * (x - y)<<" "<<i<<endl;
now = now + (1ll << i) * (x - y);
}
}
}
if (now >= 0)cout << now << endl;
else cout << -now << endl;
return ;
}
https://www.luogu.com.cn/problem/P4568

分层图板子 无需多说
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int range=2e5+5;
const int INF=1e9;
int n;
//int a[range];
int q[range];
int h[range];
int amin[range];
int bmax[range];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>h[i];
h[0]=INF;
int top=0;
q[0]=0;
for(int i=1;i<=n;i++)
{
while(top>0&&h[q[top]]<h[i])top--;
amin[i]=q[top]+1;
q[++top]=i;
// cout<<i<<" "<<top<<endl;
}
// for(int i=1;i<=n;i++)
// {
// cout<<amin[i]<<" ";
// }
// cout<<endl;
memset(q,0,sizeof q);
h[n+1]=0;
q[0]=n+1;
top=0;
for(int i=n;i>=1;i--)
{
while(top>0&&h[q[top]]>h[i])top--;
bmax[i]=q[top]-1;
q[++top]=i;
}
// for(int i=1;i<=n;i++)
// {
// cout<<bmax[i]<<" ";
// }
// cout<<endl;
int ans=0;
for(int i=n;i>=1;i--)
{
if(ans>=i)break;
for(int j=amin[i];j<i;j++)
{
if(bmax[j]>=i)
{
ans=max(ans,i-j+1);
break;
}
}
}
cout<<ans<<endl;
}
https://www.luogu.com.cn/problem/P6510

很好的一道题 考了单调栈的使用 先用单调栈找到对于一个i来说
比他小的位置 如果找不到就是本身
然后用for循环反向 找到一个 对于一个i来说 比他大的
于是 在统计答案时 我们反向统计 一旦找到 就记录
for(int i=n;i>=1;i--)
{
if(ans>=i)break;
for(int j=amin[i];j<i;j++)
{
if(bmax[j]>=i)
{
ans=max(ans,i-j+1);
break;
}
}
}
这样保证题意
https://www.luogu.com.cn/problem/CF1907E

考察的是插板法 不能发生进位的 于是 假设这一位是w 则可以三个最多两个空
于是先w+2 保证每个人都能分到 剩下就行了
cin>>n;
while(n)
{
int g=n%10;
n/=10;
ans*=(g+1)*(g+2)/2;
}
cout<<ans<<endl;

浙公网安备 33010602011771号