一些杂题的题解。
P3957 [NOIP2017 普及组] 跳房子
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define inf 1e9
using namespace std;
const int N=5e5+5;
const int mod=998244353;
int n,d,k;
int x[N],s[N],f[N];
deque<int> dq;
bool check(int g)
{
while(!dq.empty()) dq.pop_back();
int l=max(1ll,d-g),r=d+g; // 边界
for(int i=1;i<=n;i++) f[i]=-inf; // 无法到达的点 赋值为负无穷
for(int i=1;i<=n;i++)
{
if(x[i]>r) break;
if(x[i]<l) continue;
f[i]=s[i];
} // 对于一步能到达的点赋初值 (初始化
int whe=1; // 记录当前的点
for(int i=1;i<=n;i++)
{
while(!dq.empty()&&x[dq.front()]<x[i]-r) dq.pop_front(); // 去头,不在范围内的点
while(x[whe]<=x[i]-l) // 满足的点
{
whe++;
if(f[whe-1]==-inf) continue; // 不能去的点
if(x[whe-1]<x[i]-r) continue; // 不在范围内的点
while(!dq.empty()&&f[whe-1]>=f[dq.back()]) dq.pop_back(); // 去尾
dq.push_back(whe-1);
}
if(!dq.empty()) f[i]=max(f[i],f[dq.front()]+s[i]); // dp
if(f[i]>=k) return 1;
}
return 0;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int sum=0,l=1,r=0;
cin>>n>>d>>k;
for(int i=1;i<=n;i++)
{
cin>>x[i]>>s[i];
if(s[i]>0) sum+=s[i];
r=max(l,x[i]);
}
if(sum<k)
{
cout<<-1<<endl;
return 0;
}
int mid,ans;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
cout<<ans<<endl;
return 0;
}
/*
dp + 二分
n2*logn tle
只是这个距离的最大值都没办法超过k 我就要增加g
单调队列 d-g~d+g
如果暴力的话 就是每一个 f[i]=max(f[i-k])+a[i]; d-g<=k<=d+g
对于每一个i 维护一个单调队列 存f[i-k] 的最大值。
l~r
n*logd
*/
P1419
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,s,t;
int a[N];
double b[N],sum[N];
deque<int> dq;
bool check(double x)
{
while(!dq.empty()) dq.pop_back();
for(int i=1;i<=n;i++) b[i]=(double)a[i]-x;
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+b[i];
for(int i=1;i<=n;i++)
{
if(i>=s)
{
// i-s 是因为区间最小都要是s
while(!dq.empty()&&sum[i-s]<sum[dq.back()]) dq.pop_back();
dq.push_back(i-s);
}
// dq.push_back(i-s);
while(!dq.empty()&&i-dq.front()>t) dq.pop_front();
if(!dq.empty()&&sum[i]>=sum[dq.front()]) return true;
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n>>s>>t;
for(int i=1;i<=n;i++) cin>>a[i];
double ans,l,r,mid;
ans=l=-10000,r = 10000;
while (r - l > 1e-5) {
mid = (l + r) / 2;
if (check(mid))
ans=l = mid;
else r = mid;
}
printf("%.3lf\n",ans);
return 0;
}
/*
将分式转换为整式进行计算。就变成了 s[l..r]>=k*(r-l+1) 无解
(k是二分的答案,s[l..r]是l~r的区间和)
这样就变成了寻找前缀和的最大值,用一个单调队列维护。
*/
D. Make It Round
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n,m;
void solve()
{
cin>>n>>m;
int now=1,cnt=0;
while(1)
{
for(int i=1;i<=10;i++)
{
if(n*i%10==0)
{
now=i; // 寻找因子
break;
}
}
if(now>m) break;
m/=now; // 拆解因子
n=n*now/10; // 去尾0
cnt++;
}
cout<<n*m;
for(int i=1;i<=cnt;i++) cout<<0;cout<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int _=1;
cin>>_;
while(_--)
{
solve();
}
return 0;
}
/*
即神奇又清晰的思路,我还是只会笨模拟。。
*/