Loading

8.28正睿CSP七连测day1

T1

模拟即可,比较水。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N number
#define M number
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

int n;
int a[200000],len,b[200000];

int main(){
    // freopen("my.out","w",stdout);
    read(n);
    a[1]=1;len=1;
    for(int i=2;i<=n;i++){
        int tail=0,now=-1,cnt=0;
        for(int j=1;j<=len;j++){
            if(now!=a[j]){
                if(j!=1) {b[++tail]=cnt;b[++tail]=now;}
                cnt=1;now=a[j];
            }
            else cnt++;
        }
        b[++tail]=cnt;b[++tail]=now;
        for(int i=1;i<=tail;i++) a[i]=b[i];len=tail;
    }
    for(int i=1;i<=len;i++) printf("%d",a[i]);
    return 0;
}

T2

不难发现答案满足可二分性,对于区间修改,我们差分,用树状数组维护前缀和,然后二分找到第一个满足自身大于下标的地方,判断该位置左边是否满足值与下标相等即可。复杂度 \(O(k\log ^2n)\),如果用线段树并在线段树上二分可以做到一个 \(\log\)

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 10000010
#define M number
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

int n,k,b[N];
ll sum[N],a[N];

struct BIT{
    ll p[N];
    inline ll lowbit(ll x){return x&(-x);}
    inline void Add(ll w,ll val){for(int i=w;i<=n;i+=lowbit(i)) p[i]+=val;}
    inline ll AskSum(ll w){ll res=0;for(int i=w;i>=1;i-=lowbit(i)) res+=1ll*p[i];return res;}
    void Init(){
        for(int i=1;i<=n;i++){
            sum[i]=sum[i-1]+a[i];
            p[i]=sum[i]-sum[i-lowbit(i)];
        }
    }
};
BIT bit;

inline bool Check(int mid){
    return bit.AskSum(mid)>mid;
}

inline int erfen(){
    int l=1,r=n;
    while(l<r){
        int mid=(l+r)>>1;
        if(Check(mid)) r=mid;
        else l=mid+1;
    }
    return l;
}

int main(){
    // freopen("my.in","r",stdin);
    // freopen("my.out","w",stdout);
    read(k);read(n);
    for(int i=1;i<=n;i++) read(b[i]);
    for(int i=1;i<=n;i++) a[i]=b[i]-b[i-1];
    a[++n]=INF;bit.Init();int w=erfen();
    if(bit.AskSum(w-1)!=w-1) puts("NO");else puts("YES");
    for(int i=1;i<=k-1;i++){
        int l,r,val;read(l);read(r);read(val);
        bit.Add(l,val);bit.Add(r+1,-val);
        int w=erfen();
        ll now=bit.AskSum(w-1);
        if(now!=w-1||w==1) puts("NO");
        else puts("YES");
    }
    return 0;
}

T3

分块,莫队,只要是根号复杂度就能过。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 100010
#define M number
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

int kuailen,n,q,a[N],b[N],cnt[N],nowans,ans[N];

struct Ques{
    int l,r,id,ID;
    inline bool operator < (const Ques &b) const{
        return (id!=b.id)?(id<b.id):((id&1)?r<b.r:r>b.r);
    }
};
Ques ques[N]; 

inline void Add(int k){
    cnt[a[k]]++;if(cnt[a[k]]&1) nowans++;else nowans--;
}

inline void Del(int k){
    if(cnt[a[k]]&1) nowans--;else nowans++;cnt[a[k]]++;
}

int main(){
    // freopen("my.in","r",stdin);
    // freopen("my.out","w",stdout);
    read(n);kuailen=sqrt(n);for(int i=1;i<=n;i++){read(a[i]);b[i]=a[i];}
    read(q);
    for(int i=1;i<=q;i++){
        read(ques[i].l);read(ques[i].r);ques[i].id=ques[i].l/kuailen;ques[i].ID=i;
    }
    sort(ques+1,ques+q+1);sort(b+1,b+n+1);int len=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+len+1,a[i])-b;
    int l=0,r=-1;
    for(int i=1;i<=q;i++){
        while(l>ques[i].l) Add(--l);
        while(r<ques[i].r) Add(++r);
        while(l<ques[i].l) Del(l++);
        while(r>ques[i].r) Del(r--);
        ans[ques[i].ID]=nowans;
    }
    for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
    return 0;
}

T4

看了一眼 rqy 的题解,发现 rqy 真是 nb,这个题其实就是一个结论题。

\(f_n\) 为有 \(n\) 个节点的二叉树个数,\(g_n\) 表示 \(n\) 个节点的 \(f_n\) 棵二叉树的叶子总数,则答案为:

\[\frac{g_n}{f_n} \]

首先,不难发现的是 \(f_n\) 是卡特兰数,其实 \(g_n\) 也有一个性质:

我们有:

\[g_n=nf_{n-1} \]

  • 我们考虑证明:
  • 考虑所有节点数为 \(n\) 的二叉树去掉一个叶节点变成一棵 \(n-1\) 个节点的二叉树。那么因为所有节点数为 \(n-1\) 的二叉树能够有 \(n\) 种方案添加一个叶子节点变成一棵 \(n\) 个结点的二叉树(我们一会在证明这个结论),所以我们如果尝试分别去掉 \(n\) 个节点的二叉树的每一个叶子,对所有的 \(n\) 个节点的二叉树都这么做的话,会发现所有 \(n-1\) 个节点的二叉树都被算了 \(n\) 遍,不难发现,因为是去掉每个叶子节点,所以就有 \(g_n=nf_{n-1}\)
  • 现在我们来证明:所有节点数为 \(n-1\) 的二叉树能够有 \(n\) 种方案添加一个叶子节点变成一棵 \(n\) 个结点的二叉树。
  • 考虑到把一棵二叉树上所有的边定向,全部定向成父亲到儿子的方向,那么我们可以发现如果一个节点的出度小于 \(2\) 的话,就可以放上面添加 \(1\)\(2\) 个叶子节点。考虑整棵树一共有 \(n\) 个点,加入每个点的出度为 \(2\) 的话总出度为 \(2n\),但是一共有 \(n-1\) 条边,那么剩下的出度为 \(2n-(n-1)=n+1\),也就是说可以添加 \(n+1\) 条个儿子。

这个规律是达标发现,然后考虑证明。需要有一定的打表能力。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define int long long
#define uint unsigned int
#define ull unsigned long long
#define N number
#define M number
using namespace std;

const int INF=0x3f3f3f3f;
const ull mod=2148473647;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

int n;

inline ll ksc(ll x,ll y,ll mod){
	ll z=(ld)x/mod*y;
	ll res=(ull)x*y-(ull)mod*z;
	return (res%mod+mod)%mod;
}


inline int ksm(int a,int b,int mod){
    int res=1;
    while(b){if(b&1) res=ksc(res,a,mod);a=ksc(a,a,mod);b>>=1;}
    return res;
}

signed main(){
    read(n);
    // cout<<n*(n+1)%mod<<endl;
    // cout<<ksm(4*n-2,mod-2,mod)<<endl;
    printf("%lld\n",ksc(ksc(n,(n+1),mod),ksm(4*n-2,mod-2,mod),mod));
    return 0;
}
posted @ 2021-08-30 08:28  hyl天梦  阅读(135)  评论(0编辑  收藏  举报