• 【被虐】第三场选拔赛补题


    补题时间。。。

    这回出题人出的都是mbg风格的题。。。话不多说,挑几个有意思的说说。

    B题,题意给定(nleqslant 10^9),求

    [sum_{pleqslant n}frac 1p, (p is prime) ]

    的值并四舍五入取整。

    显然直接求是不行的,因为会超时,事实上这题我目前还没发现有什么低于线性的算法,所以这题差不多是个结论题。结论是,在(10^9)的范围内,该和式的值取整后不会超过3,所以只要二分找出几个值的边界即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=6e6+5;
    int prime[N],cnt;
    bool vis[N];
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		int n;
    		scanf("%d",&n);
    		if(n<3) printf("0
    ");
    		else if(n<29) printf("1
    ");
    		else if(n<11789) printf("2
    ");
    		else printf("3
    ");
    	}
    	return 0;
    }
    

    F题:

    image-20201124205304429

    一眼看上去很牛逼,其实很沙比。。。就模拟就行了。。。

    但是这题正好触及到了我的知识盲区(动态空间数组),只要会vector就行了(或手写链表)。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    #define i8 __int128
    #define rep(i,l,r) for(int i=l;i<=r;i++)
    #define vrep(i,__v) for(int i=0;i<__v.size();i++)
    inline i8 read()
    {
        i8 ret=0,sgn=1;
        char c=getchar();
        while(c<'0'||c>'9')
        {if(c=='-') sgn=-1;c=getchar();}
        while(c>='0'&&c<='9')
        {ret=ret*10+c-'0';c=getchar();}
        return ret*sgn;
    }
    void write(i8 x)
    {
        if(x<0) x=-x,putchar('-');
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    const int N=1e6+5;
    vector<int> v[N];
    int main()
    {
       int n,x;
       scanf("%d",&n);
       rep(i,1,n)
       {
           scanf("%d",&x);
           v[x].push_back(i);
       }
       int ans=2e9;
       rep(i,1,n)
       {
           scanf("%d",&x);
           vrep(j,v[x])
           {
               ans=min(ans,abs(v[x][j]-i));
           }
       }
       if(ans==2e9) printf("-1
    ");
       else printf("%d
    ",ans);
       return 0;
    }
    

    H题:给一颗有根树,树节点有权值,有两种操作:1.单点修改,将一个节点的权值+v。2.查询,求某节点到树根的简单路径上所有点权平方和,答案对(2^{64})取模。

    这个题考试的时候想到了树链剖分 ,但是死活调不出来,自己以为是树链剖分写次了,结果没想到是一个前所未见的玄学错误。。。我对模数赋值的时候直接赋值成了(2^{64})。。。然后成功RE。。。(事实上这个数在计算机里根本不存在。。。),这也侧面证明了树剖没错。。。哭了,然而自己赛后纠错后还是T了(树剖复杂度真高)。事实上,存在一种很简单的算法,仅仅需要搞出树的dfs序即可。我们维护一个类似前缀和的东西,维护每个点到根节点路径的答案,在dfs的时候可以直接求出来,考虑一次单点修改只对某节点及其子树的答案有影响,我们再维护一个树状数组,差分修改,然后求的时候直接查询树状数组就好了。(其实很简单)

    (小技巧:取模(2^{64})可以用unsigned long long存储数据,自然溢出就可以了。然而我用的int128也不是不可以。。。)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;//simplify long long
    typedef unsigned long long ull;
    typedef double db;
    typedef long double ldb;
    #define inf 0x3f3f3f3f
    #define pi 3.14159265358979
    #define rep(i, l, r) for(int i = l; i <= r; i ++)
    #define lop(i, r, l) for(int i = r; i >= l; i --)
    #define step(i, l, r, __step) for(int i = l; i <= r; i += __step)
    #define revp(i, r, l, __step) for(int i = r; i >= l; i -= __step)
    #define reg regsiter
    #define RI regsiter int
    #define RL regsiter long long
    #define rerep(i, l, r) for(regsiter int i = l; i <= r; i ++)
    #define relop(i, r, l) for(regsiter int i = r; i >= l; i --)
    #define i8 __int128
    //#define __int128 ll//don't forget delete it in contest!
    inline i8 read()//fast read
    {
    	i8 ret = 0, sgn = 1;
    	char chr = getchar();
    	while(chr < '0' || chr > '9')
    	{if(chr == '-') sgn = -1; chr = getchar();}
    	while(chr >= '0' && chr <= '9')
    	{ret = ret * 10 + chr - '0'; chr = getchar();}
    	return ret * sgn;
    }
    void write(i8 x)//int128's output
    {
    	if(x < 0) putchar('-'), x = -x;
    	if(x > 9) write(x / 10);
    	putchar(x % 10 + '0');
    }
    const int N = 1e6 + 5;
    const int M = 2e5 + 5;
    int n,m,S;
    struct edge{
    	int to,nxt;
    }e[N<<1];
    int head[N],tot;
    void adde(int f,int t)
    {
    	e[++tot]=(edge){t,head[f]};
    	head[f]=tot;
    }
    int deep[N],fa[N],siz[N];
    int inseg[N],intr[N],scnt=0;
    i8 sum[N],num[N],mod=(1ll<<63);
    void dfs(int u,int f)
    {
    	deep[u]=deep[f]+1;
    	sum[u]=sum[f]+num[u]*num[u];
    	fa[u]=f;
    	siz[u]=1;
    	inseg[u]=++scnt;
    	intr[scnt]=u;
    	for(int i=head[u];i;i=e[i].nxt)
    	{
    		int v=e[i].to;
    		if(v==f) continue;
    		dfs(v,u);
    		siz[u]+=siz[v];
    	}
    }
    i8 atr[N];
    #define lowbit(x) x&-x
    void modify(int x,i8 v)
    {
    	while(x<=n)
    	{
    		atr[x]+=v,atr[x]%=mod;
    		x+=lowbit(x);
    	}
    }
    i8 ask(int x)
    {
    	i8 ret=0;
    	while(x)
    	{
    		ret+=atr[x],ret%=mod;
    		x-=lowbit(x);
    	}
    	return ret;
    }
    int main()
    {
    	mod*=2;
    	scanf("%d%d%d",&n,&m,&S);
    	rep(i,1,n) num[i]=read();
    	int a,b;
    	rep(i,1,n-1)
    	{
    		scanf("%d%d",&a,&b);
    		adde(a,b);
    		adde(b,a);
    	}
    	dfs(S,0);
    	i8 v,w;
    	while(m--)
    	{
    		scanf("%d%d",&a,&b);
    		if(a==1)
    		{
    			v=read();
    			w=2ll*v*num[b]+v*v;
    			modify(inseg[b],w);
    			modify(inseg[b]+siz[b],-w);
    			num[b]+=v;
    		}
    		else
    		{
    			w=ask(inseg[b]);
    			write((w+sum[b])%mod);
    			putchar('
    ');
    		}
    	}
    	return 0;
    }
    

    I题:题目很短,求

    [sum_{i=l}^rC_i^k ]

    [kleqslant200,l,rleqslant 10^9 ]

    其实是个神仙题。。。把式子拆开看:

    [C_l^k+C_{l+1}^k+cdots+C_r^k ]

    这个式子看不出什么来,对这个式子进行一次转化,由

    [C_n^m=C_n^{n-m} ]

    [C_l^{l-k}+C_{l+1}^{l-k+1}+cdots+C_r^{r-k} ]

    [=C_l^{l-k}+C_l^{l-k-1}+C_{l+1}^{l-k+1}+cdots+C_r^{r-k}-C_l^{l-k-1} ]

    前两项可以由杨辉三角公式合并,此时变为

    [C_{l+1}^{l-k}+C_{l+1}^{l-k+1}+C_{l+2}^{l-k+2}+cdots+C_r^{r-k}-C_l^{l-k-1} ]

    此时新的两项又可以同样的方式合并,一直合并到最后,则原式等于

    [C_{r+1}^{r-k}-C_l^{l-k-1} ]

    虽然已经化到最简形式了,但是此时还是无法卢卡斯求。我们注意到k很小,并对组合数阶乘展开,发现最后只需要计算小于200项的连乘和k阶乘的逆元,于是连乘暴力求就完事了,阶乘可以暴力也可以先预处理。

    代码很简单

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define i8 __int128
    #define __int128 ll
    #define rep(i,l,r) for(int i=l;i<=r;i++)
    ll mod=1e9+7;
    ll f[1005];
    void init()
    {
    	f[0]=1;
    	rep(i,1,988) f[i]=1ll*i*f[i-1],f[i]%=mod;
    }
    ll ksm(ll x,ll y)
    {
    	ll ret=1;
    	while(y)
    	{
    		if(y&1) ret*=x,ret%=mod;
    		x*=x,x%=mod;
    		y>>=1;
    	}
    	return ret;
    }
    ll inv(ll x)
    {
    	return ksm(x,mod-2);
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	init();
    	while(T--)
    	{
    		ll l,r,k;
    		scanf("%lld%lld%lld",&l,&r,&k);
    		ll ans1=1;
    		rep(i,max(r-k+1,0ll),r+1) ans1*=1ll*i,ans1%=mod;
    		ans1*=inv(f[k+1]),ans1%=mod;
    		ll ans2=1;
    		rep(i,max(0ll,l-k),l) ans2*=1ll*i,ans2%=mod;
    		ans2*=inv(f[k+1]),ans2%=mod;
    		ll ans=ans1-ans2;
    		ans=(ans%mod+mod)%mod;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux磁盘挂载
    3个方法解决百度网盘限速 (2018-07-20)
    mysql状态分析之show global status
    Cgroups子系统介绍
    Go语言 关键字:defer
    Go语言 map的实现
    Go语言 基本类型
    MySQL 监控指标
    sshpass的使用方法
    C++11 std::ref使用场景
  • 原文地址:https://www.cnblogs.com/loi-frank/p/14032688.html
Copyright © 2020-2023  润新知