Codeforces Round 917 (Div. 2)(D树状数组+二进制求逆序对?)

A:如果负数是偶数个,不需要改变

否则把其中一个数变成0即可

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
 
const long long inf=1e17;
using node=tuple<int,int,int,int>;
int n,m,k;
int gcd(int a, int b)  // 欧几里得算法
{
    return b ? gcd(b, a % b) : a;
}
int lcm(int a,int b){
    return a*b/gcd(a,b);
}
int a[N];
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int mx=0;
    bool ok=true;
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==0){
            cout<<0<<"\n";
            return ;
        } 
        if(a[i]<0) ok=false,cnt++;
    }
    if(cnt&1){
        cout<<0<<"\n";
        return ;
    }
    else{
        cout<<1<<"\n";
        cout<<1<<" "<<"0\n";
    }
    //cout<<max(mx,mn)<<"\n";
}
 
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
   
    cin>>t;
    while(t--) solve();
}

B:

操作题先想操作的性质

可以手玩一下

可以发现操作如果前面有两个字母固定不能删了,那么后面就全都不能操作了,都是完整的一个后缀了

即最后格式肯定是 前面一个字母+一个后缀

所以对于每个后缀求前面有多少个不同的字母就行了

注意后缀为空的时候也是要算的

一个字母加空后缀也是合法的

且因为每个后缀长度不同贡献不同

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;

typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
 
const long long inf=1e17;
using node=tuple<int,int,int,int>;
int n,m,k;

int a[N],b[N];
void solve()
{
    string s;cin>>n>>s;
    set<char> st;
    int res=0,now=0;
    
    for(auto x:s)
    {
        res+=st.size();
        st.insert(x);
    }
    res+=st.size();
    cout<<res<<"\n";
}
 
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
   
    cin>>t;
    while(t--) solve();
}

C:

操作题先想操作

如果重置了数组,且因为b[i]都大于0

即肯定有一个前缀加一

因为变成全0后,增加一个后缀,不论怎么加,因为他要求的是递增的,所以最多只会让一个位置下标等于数值

所以如果充值了,最好的贡献是加一个前缀再加一分 让a[1]=1满足就行

所以直接枚举哪个位置开始操作第二个位置就行了,

我是直接暴力到1e5了,差不多是,因为会存在一些位置

比如 [0,0,0,0,0,1,2,3,4,5,6]

[10]

这个情况,所以我的建议是直接拉满到1e5

实际最多需要4000估计就肯定操作第二个操作了3

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;

typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
 
const long long inf=1e17;
using node=tuple<int,int,int,int>;
int n,m,k;

int a[N],b[N];
void solve()
{
    int d;
    cin>>n>>k>>d;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=0;i<k;i++) cin>>b[i];
    int res=0;
    for(int i=1;i<=min(d,100000);i++)
    {
        int cnt=max(0,(d-i)/2);
        int c=0;
        for(int j=1;j<=n;j++)
        {
            if(a[j]==j) c++;
        }
        res=max(res,c+cnt);
        for(int j=1;j<=b[(i-1)%k];j++){
            a[j]++;
        }
       // cout<<c<<"\n";
    }
    cout<<res<<"\n";
}
 
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
   
    cin>>t;
    while(t--) solve();
}

D:

记住b[i]是连续的!!!!!!

分开计算两个贡献

自己内部 a[i]里面不同b[i]的贡献

和不同a[i]里面的贡献

第一个贡献就是b[i]的逆序对*n

第二个贡献比较麻烦

上上周的牛客小白赛最后一题你们可以做一做

就是如果乘2^19已经大于了a[i]里面的全部数,那么后面的贡献就全是

(k-18)*(k-19)/2%mod*i

就是因为a[i]乘2^19肯定比其他数都大,所以剩下的k-18个数都会大于全部a[i]

第一个循环是找向上第一个跨越长度的

第二个循环是找向下跨越长度的

0.0算了放弃解释了思密达

Codeforces Round 917 (A-D)讲解_哔哩哔哩_bilibili

看这个视频吧

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
 
const long long inf=1e17;
using node=tuple<int,int,int,int>;
int n,m,k;

int a[N],b[N];
class BitTree {
    public:
	vector<int> tree;
	int n;
    BitTree(int _n) : n(_n) {
	    tree.resize(n+1);
	    fill(tree.begin(),tree.end(),0);
	}
	inline int lowbit(int x) { return x&-x; }
	inline void Modify(int x,int v) {
		for(;x;x-=lowbit(x)) tree[x]+=v;
	}
	inline int q(int x) {
		int ret=0;
		for(;x<=n;x+=lowbit(x)) ret+=tree[x];
		return ret;
	}
	inline int Query(int l,int r) {
		return q(r)-q(l-1);
	}
};
int qmi(int a, int k, int p)  // 求a^k mod p
{
    int res = 1 % p;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}

void solve()
{
	int n,k;
	cin>>n>>k;
	vector<int> p(n),q(k);
	BitTree T1(k),T2(2*n-1);
	for(int i=0;i<n;++i)cin>>p[i];
	for(int i=0;i<k;++i)cin>>q[i],++q[i];
	int ans=0,sum=0;
	for(int i=0;i<k;++i){
		sum+=T1.q(q[i]);
		T1.Modify(q[i],1);
	}
	ans=sum%mod*n%mod;
	for(int i=0;i<n;++i){
		for(int j=0;j<min(k,19ll);++j){
			ans=(ans+1ll*T2.q(min(2ll*n,(LL)p[i]<<j))*(k-j))%mod;
		}
		for(int j=1;j<min(k,19ll);++j){
			ans=(ans+1ll*T2.q((p[i]>>j)+1)*(k-j))%mod;
		}
		if(k>19)ans=(ans+1ll*(k-18)*(k-19)/2%mod*i)%mod;
		T2.Modify(p[i],1);
	}
	cout<<ans<<'\n';
}
 
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
   
    cin>>t;
    while(t--) solve();
}

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值