2020牛客寒假算法基础集训营第四场

子段乘积

尺取法就完事熬

#include <iostream>
#include <cstring>
 
using namespace std;
typedef long long ll;
int mod = 998244353;
template<typename T> void read(T &x){
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int sub(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int sq(int x){return 1ll*x*x%mod;}
int pow(int a,int b){return b == 0 ? 1 : ( b&1 ? mul(a,sq(pow(a,b/2))) : sq(pow(a,b/2)));}
 
int n,k,a[1000010];
int main(){
    read(n);read(k);
    for(int i=1;i<=n;i++){
        read(a[i]);
    }
    int ans = 0,md = 1,cnt = 0;
    for(int i=1;i<=k;i++){
        if(a[i] == 0){
            cnt++;
        }else{
            md = mul(md,a[i]);
        }
    }
    for(int i=1;i+k-1<=n;i++){
        if(!cnt)ans = max(ans,md);
        if(a[i] == 0)cnt--;
        else md = mul(md,pow(a[i],mod-2));
        if(a[i+k] == 0)cnt++;
        else md = mul(md,a[i+k]);
    }
    cout<<ans<<endl;
    return 0;
}

  子段异或,首先从第一个数开始不断地异或到最后,异或过程中一个值重复出现,就说明这两个值之间出现一段异或起来为0的;

#include <bits/stdc++.h>
 
#define debug(x) cerr<<#x<<'='<<x<<endl
#define set0(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
template<typename T> void read(T &x){
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
 
ll n,a[200010],ans = 0;
map<ll,int> Mp;
int main() {
    read(n);
    ll csu = 0;
    Mp[0] = 1;
    for(int i=0;i<n;i++){
        read(a[i]);
        csu^=a[i];
        ans+=Mp[csu];
        Mp[csu]+=1;
    }
    cout<<ans<<endl;
    return 0;
}

  

最小表达式

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
int cnt[20];
int sum[500050];
 
char s[500050];
int main() {
    cin>>s;
    int ccnt = 1;
    int n = strlen(s);
    for(int i=0;i<n;i++){
        if(isdigit(s[i])){
            cnt[s[i]-'0']+=1;
        }else{
            ccnt+=1;
        }
    }
    int p = 0,cp = 0;
    for(int i=10;i>=1;i--){
        while(cnt[i]){
            sum[cp]+=i;
            cnt[i]-=1;
            p = (p+1)%ccnt;
            if(p == 0)cp+=1;
        }
    }
    for(int i=0;i<500010;i++){
        sum[i+1]+=sum[i]/10;
        sum[i]%=10;
    }
    int opt = 0;
    for(int i=500010;i>=0;i--){
        if(opt || sum[i]){
            cout<<sum[i];
            opt = 1;
        }
    }
    cout<<endl;
    return 0;
}

  

树上博弈

作者:nocriz
链接:https://www.nowcoder.com/discuss/365889
来源:牛客网

首先,注意到输掉的唯一方法是自己的唯一一条边有另一个人,那么自己一定是在叶子上。
令两个人之间的距离为D。请注意,每人行动后D增加1或减少1。 因此,每有人走一步D的奇偶性都会改变。
假设最初,在牛牛移动之前,D是偶数。 那么当牛牛移动时D将始终为偶数,而当牛妹移动时D将始终为奇数。
请注意,只要牛牛和牛妹的令牌位于相邻的节点中,D=1。因此,如果D为偶数,则他们不在相邻的单元格中,并且牛牛始终可以移动。
另一方面,由于牛牛总是可以移动,因此他可以向牛妹的方向移动,将牛妹必然会最终移动到叶子上。同样,如果最初D是奇数,则牛妹获胜。
因此,答案取决于距离的奇偶性:如果是偶数,则牛牛获胜,否则牛妹获胜。
可以发现,只有牛牛的初始位置和牛妹的初始位置距离为偶数时,牛牛获胜。只需要分别求出深度为奇数的点和深度为偶数的点的数量即可。

#include <bits/stdc++.h>
 
#define debug(x) cerr<<#x<<'='<<x<<endl
#define set0(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
template<typename T> void read(T &x){
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
    read(first);
    read(args...);
}
 
int n,q,x,y,depth[1000010];
ll cnt[2];
 
int main() {
    read(n);
    depth[1] = 0;
    cnt[0] = 1;
    for(int i=2;i<=n;i++){
        int cc;
        read(cc);
        depth[i] = depth[cc]^1;
        cnt[depth[i]]+=1;
    }
    cout<<cnt[0]*(cnt[0]-1)+cnt[1]*(cnt[1]-1)<<endl;
    return 0;
}

  作者:nocriz
链接:https://www.nowcoder.com/discuss/365889
来源:牛客网

音乐鉴赏

如果随机占比为 xxx ,一个人分数为 scorescorescore ,那么他优秀的概率为 (score−90)(1−x)90x\frac{(score-90)(1-x)}{90x}90x(score90)(1x)

这个概率可以这么计算:首先把分数减90,大于0就优秀,那么就变成(score−90)∗(1−x)−y∗x≥0(score-90)*(1-x)-y*x\ge 0(score90)(1x)yx0,其中y是一个随机的0到90之间的数字。(score−90)∗(1−x)≥y∗x(score-90)*(1-x)\ge y*x(score90)(1x)yx,(score−90)∗(1−x)x≥y\frac{(score-90)*(1-x)}{x}\ge yx(score90)(1x)y,这个概率就是上面所写的概率。

E=∑i=1n(scorei−90)(1−x)90x=0.1nE=\sum_{i=1}^{n} \frac{(score_i-90)(1-x)}{90x}=0.1nE=i=1n90x(scorei90)(1x)=0.1n,解方程可知答案为∑i=1n(scorei−90)9n+∑i=1n(scorei−90)\frac{\sum_{i=1}^n(score_i-90)}{9n+\sum_{i=1}^n(score_i-90)}9n+i=1n(scorei90)i=1n(scorei90)

也可以使用二分求解。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,sum=0,tp=0;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>tp;
        sum+=tp;
    }
    double S = sum-90*n;
    cout<<setprecision(2)<<fixed;
    cout<<(S/(9*n+S)*100)<<"%\n";
    return 0;
}



匹配星星

这道题目可以使用贪心算法求解。先按照X坐标从小到大排序,然后对于每一个点

    • 如果Z = 1,查询比他X坐标小的Y坐标最大的Z= 0的点,进行配对,如果配对成功则将那个点都从候选点中排除。
    • 如果Z = 0,将该点加入候选点。
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
 
using namespace std;
typedef long long ll;
 
struct P{
    int a,b,c;
    bool operator < (const P &rhs) const{
        if(a == rhs.a)return c>rhs.c;
        return a<rhs.a;
    }
}alp[300030];
int n;
int main() {
    cin>>n;
    for(int i=0;i<n;i++) cin>>alp[i].a>>alp[i].b>>alp[i].c;
    sort(alp,alp+n);
    multiset<int> pool;
    multiset<int>::iterator it;
    int ans = 0;
    for(int i=0;i<n;i++){
        if(alp[i].c){
            it = pool.lower_bound(alp[i].b);
            if(it!=pool.begin()){
                --it;
                pool.erase(it);
                ans+=1;
            }
        }else{
            pool.insert(alp[i].b);
        }
    }
    cout<<ans<<endl;
     
    return 0;
}

  

H - 坐火车
线段树写的,我看出题人那个思维我还是不习惯,自己想了一个写法。
先用g统计1到n颜色的总数量,然后gg统计1到i-1的颜色数量,每次都只改变一个点,我们只需要更新这个点的颜色贡献,贡献值为res=1ll*(g[f[i].c]-1-gg[f[i].c])*gg[f[i].c]; 然后查询就好了。这题有点卡常,加了个ll rr就A了

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=5e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
struct in
{
    int c,l,r;
}f[N];
LL g[N];
LL gg[N];
LL sum[N<<2];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
void update(int k,int l,int r,int pos,LL v)
{
    if(l==r){
        sum[k]=v;
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=pos) update(ls,pos,v);
    else update(rs,pos,v);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}
LL query(int k,int l,int r,int x,int y)
{
    if(x<=l&&r<=y){
        return sum[k];
    }
    int mid=(l+r)>>1;
    LL res=0;
    if(mid>=x) res+=query(ls,x,y);
    if(mid<y) res+=query(rs,x,y);
    return res;
}
int main()
{
    r(n);
    int ll=INF,rr=0;
    FOR(i,1,n){
        rrr(f[i].c,f[i].l,f[i].r);
        g[f[i].c]++;
        ll=min(f[i].c,ll);
        rr=max(f[i].c,rr);
    }
    LL res;
    FOR(i,1,n){
        if(f[i].l<=f[i].c&&f[i].c<=f[i].r){
            res=1ll*(g[f[i].c]-1-gg[f[i].c])*gg[f[i].c];
            update(1,ll,rr,f[i].c,res);
        }
        cout<<query(1,ll,rr,f[i].l,f[i].r)<<' ';
        gg[f[i].c]++;
        res=1ll*(g[f[i].c]-gg[f[i].c])*gg[f[i].c];
        update(1,ll,rr,f[i].c,res);
    }
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/hgangang/p/12304421.html