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;
}
posted @ 2022-10-17 20:05  wzx_believer  阅读(36)  评论(0编辑  收藏  举报