sduwh xcpc选拔赛(1)
质量很高的几道题
A October的落叶
签到题 没啥说的
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=4e5+5;
int T,n,k,res;
ll sum;
int a[maxn];
void solve();
int main(){
cin>>T;
while(T--)solve();
return 0;
}
void solve(){
sum=0,res=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++)scanf("%d",&a[i]);
sort(a+1,a+1+k);
for(int i=k;i>=1;i--){
if(sum<a[i])
sum+=(n-a[i]),res++;
else break;
}
cout<<res<<endl;
}
B October的滋蹦
分析:
dp[i][0/1] 表示前i个 以第i个0/3为结尾的字符串数量
转移:对于第i个 可以他自己开一个字符串 也可以连接以前的字符串
dp[i][0]=dp[i][1]+1
dp[i][1]=dp[i][0]+1
特别的 如果为? 是会重复计数的 所以要减去重复计数的部分
? 会重复计数 1 次
?? 会重复计数 1+2次
???会重复计数1+2+3次
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=2e5+5;
int T,len;
ll dp[maxn][2];
string s;
ll ans,sum;
void solve();
int main(){
cin>>T;
while(T--)solve();
return 0;
}
void solve(){
ans=0,sum=0;
memset(dp,0,sizeof(dp));
cin>>s;
s='?'+s;
len=s.size();
for(int i=1;i<len;i++){
if(s[i]=='0')
dp[i][0]=dp[i-1][1]+1;
else if(s[i]=='3')
dp[i][1]=dp[i-1][0]+1;
else if(s[i]=='?')
dp[i][1]=dp[i-1][0]+1,dp[i][0]=dp[i-1][1]+1;
ans+=(dp[i][1]+dp[i][0]);
if(s[i]=='?')sum++,ans-=sum;
else sum=0;
}
printf("%lld\n",ans);
}
E October的石子游戏
遇到原题了
https://www.cnblogs.com/wzxbeliever/p/11688267.html
F October的简单题
九个月前做的一道题 但是任然有点印象
https://www.cnblogs.com/wzxbeliever/p/15811091.html
C October的难题
题意:求区间最大减最小等于k的区间个数
首先想到这么一道题
https://ac.nowcoder.com/acm/contest/6874/I
求区间最大减最小大于k的区间个数
分析:
首先想到区间最大最小用单调队列分别维护
当确定一个区间的左端点l 后,区间最小值和最大值是关于区间右端点r 的一个单峰函数。
那么对于一个左端点l,我们只需要找到一个最小的r 使其最大值和最小值之差大于k ,那么[r,n]中每一个值作右端点都是合法的。
直接对答案加上贡献,然后将左端点右推一位,继续找到其对应的最小右端点即可。
然后在枚举区间右端点的过程中维护单调性,在左端点右移的时候维护队列中下标要在当前区间中即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int maxn=1e7+100;
const int mod=1e9;
ll a[maxn];
ll qmax[maxn];
ll qmin[maxn];
int main(){
int n;
ll b,c,k;
cin>>n>>k;
cin>>a[0]>>b>>c;
for(int i=1;i<=n;i++){
a[i]=(1ll*a[i-1]*b+c)%mod;
}
ll ans=0,l=1,h1=1,t1=0,h2=1,t2=0;
for(int i=1;i<=n;i++){
while(h1<=t1&&a[i]>=a[qmax[t1]]) t1--;
while(h2<=t2&&a[i]<=a[qmin[t2]]) t2--;
qmax[++t1]=i;
qmin[++t2]=i;
while(h1<=t1&&h2<=t2&&a[qmax[h1]]-a[qmin[h2]]>k){
ans+=n-i+1;
l++;
if(qmax[h1]<l) h1++;
if(qmin[h2]<l) h2++;
}
}
cout<<ans<<endl;
}
回到本题来
不难想到用容斥来求
(MAX-MIN=K) 的方案数=总方案数 - (MAX-MIN<K) 的方案数 - (MAX-MIN >K) 的方案数
现在关键在于<k的方案怎么求
我们可以发现如果区间[ l , r ] 满足题意那么区间[ l + 1 , r ] 也满足题意
所以我们只要对每一个r 求出最左边的l 使[ l , r ] 满足题意,那么右端点为r 的满足条件的区间一共有r - l + 1 个
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e6+5;
ll n,k;
int a[maxn];
ll ans,sum;
deque<int>Q1,Q2,Q3,Q4;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int l1=1,l2=1;
for(int i=1;i<=n;i++){
while(!Q1.empty()&&a[i]>a[Q1.back()])Q1.pop_back();
while(!Q2.empty()&&a[i]<a[Q2.back()])Q2.pop_back();
while(!Q3.empty()&&a[i]>a[Q3.back()])Q3.pop_back();
while(!Q4.empty()&&a[i]<a[Q4.back()])Q4.pop_back();
Q1.push_back(i);
Q2.push_back(i);
Q3.push_back(i);
Q4.push_back(i);
while(!Q1.empty()&&!Q2.empty()&&a[Q1.front()]-a[Q2.front()]>k){
ans+=(n-i+1);
l1++;
while(!Q1.empty()&&Q1.front()<l1)Q1.pop_front();
while(!Q2.empty()&&Q2.front()<l1)Q2.pop_front();
}
while(!Q3.empty()&&!Q4.empty()&&a[Q3.front()]-a[Q4.front()]>=k){
l2++;
while(!Q3.empty()&&Q3.front()<l2)Q3.pop_front();
while(!Q4.empty()&&Q4.front()<l2)Q4.pop_front();
}
ans+=(i-l2+1);
}
cout<<n*(n+1)/2-ans<<endl;
return 0;
}
D Candy Hunter
分析:
读题啊 比赛的时候没有注意到 bi一定大于b pi 这个条件
有了这个条件 直接维护倍增 暴力跳到最高层就好
#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline T next() {
T x;
cin >> x;
return x;
}
void untie() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
using LL = long long;
void solve() {
int q = next<int>();
vector<pair<int, int>> tree(q + 1);
vector<vector<int>> fa(q + 1);
tree[0].first = next<int>();
tree[0].second = next<int>();
fa[0].resize(21);
fa[0][0] = 0;
vector<pair<int, int>> queries;
for (int i = 1; i <= q; i++) {
int op = next<int>();
if (op == 1) {
fa[i].resize(21);
fa[i][0] = next<int>();
tree[i].first = next<int>();
tree[i].second = next<int>();
} else {
int v = next<int>();
int w = next<int>();
queries.push_back(make_pair(v, w));
}
}
for (int j = 1; j <= 20; j++) {
for (int i = 0; i <= q; i++) {
if (fa[i].size()) {
fa[i][j] = fa[fa[i][j - 1]][j - 1];
}
}
}
for (auto p : queries) {
int v = p.first;
int w = p.second;
int usage = 0;
LL ans = 0;
while (usage < w && tree[v].first) {
int p = v;
for (int i = 20; i >= 0; i--) {
if (tree[fa[p][i]].first) {
p = fa[p][i];
}
}
int x = min(w - usage, tree[p].first);
usage += x;
tree[p].first -= x;
ans += 1ll * x * tree[p].second;
}
cout << usage << ' ' << ans << '\n';
}
}
int main() {
untie();
int T = 1; // next<int>();
while (T--) {
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2019-10-17 博弈论训练之一
2019-10-17 动态规划训练之十三
2019-10-17 杂题训练之七
2019-10-17 奇技淫巧训练之八