2021牛客暑期多校训练营1

2021牛客暑期多校训练营1

2021牛客暑期多校训练营1

G

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-laWrTX4D-1627219079381)(C:\Users\wxy\AppData\Roaming\Typora\typora-user-images\image-20210721144108389.png)]

首先需要了解的是题目需要我们输出的是绝对值的差值,在abs运算中一定是大数去减去小数的,所以题目是有一个隐藏的无限制的次数的操作,就是交换a,b序列中相同位置的值。所以为了方便理解可以将a序列看做大数序列,b序列看作小数序列。

现在我们进行k次操作,使得答案的值变大。那么在什么时候答案的值会变大呢?

如果b序列中的某个数bi,比a序列中的某个数aj要大的话,那么显然将bi和aj互换的话,答案是会变大的。因为是2个较大的数在相减,和2个较小的数相减,我们的目的是要较大的数减去较小的数,这些答案就会是最优。

那么答案增加了多少呢,ai-bi+aj-bj =>bi-aj+ai-aj 发现增加了2*(bj-ai);

那么我们只需要将大数和小数排序,如果发现有小数大于大数的话,就答案增加。如果序列已经是最有的话,那么就不需要再去交换大小数了,要及时break;

如果我们已经break后,k还没用完怎么办?我们只需要随意在同一个序列中交换就可以,最后的答案是不会改变的。

int a[5 * maxn], b[5 * maxn];
int dmin[5 * maxn], dmax[5 * maxn];

signed main()
{
	//ios::sync_with_stdio(0);
	//cin.tie(0),cout.tie(0);

	int n = read(), k = read();
	rep(i, 1, n) a[i] = read();
	rep(i, 1, n) b[i] = read();

	ll ans = 0;

	rep(i, 1, n)
	{
		ans = ans + abs(a[i] - b[i]);
		dmax[i] = 2 * max(a[i], b[i]);
		dmin[i] = 2 * min(a[i], b[i]);
	}

	sort(dmax + 1, dmax + 1 + n);
	sort(dmin + 1, dmin + 1 + n, greater<int>());

	for (int i = 1; i <= n && i <= k; ++i)
	{
		if (dmin[i] < dmax[i]) break;
		ans = ans + dmin[i] - dmax[i];
	}
	out(ans);
	return 0;
}

A

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mGkhrLJc-1627219079383)(C:\Users\wxy\AppData\Roaming\Typora\typora-user-images\image-20210721150107248.png)]

本题SG打表太慢了…

一个很重要的结论就是,如果某堆石子为i的话,那么另外一堆石子只会有一种情况满足后手胜利。

证:

设( i , p ) 和(i,q)都为选择一次后手胜利且p>q,则先手可以从i,p转移到i,q,而得到先手胜,与假设矛盾。

所以可以利用这个结论来愉快的打表,知道先手必败的状态,可以反向得到后手必胜的状态。

sg[0][0] = 0; 
for(int i = 0;i<=5000;++i)
        for(int j = 0;j<=5000;++j)
        {
            if(!sg[i][j]) 
            {
                for(int k = 1;i+k<=5000;++k)
                    for(int s = 0;j+s*k<=5000;++s)
                        sg[i+k][j+s*k] = 1;
                         
                for(int k = 1;j+k<=5000;++k)
                    for(int s = 0;i+s*k<=5000;++s)
                        sg[i+s*k][j+k] = 1;
            }
        }		
      

这个打表看起来是一个n^3的时间,但是!sg[i] [j]只会有5000个(结论),而枚举倍速是logn的时间

所以实际上是一个n^2logn的时间复杂度。

D

kmp签到

signed main()
{
	//ios::sync_with_stdio(0);
	//cin.tie(0),cout.tie(0);
	
	int n = read(),m = read();
	rep(i,0,n-1) cin>>a[i]; 
	cin>>b;
	
	int len = b.size();
	
	string c = "";
	rep(i,1,len) c = '0'+c;
	
	int cnt = 0;
	
	rep(i,0,n-1)
	{
		int pos = 0;
	
		while( (pos = a[i].find(c,pos)) != -1)
		{	 
			cnt++;
			pos++;
		}
	}
	
	out(cnt);
	return 0;
}

B

签到

signed main()
{
	//ios::sync_with_stdio(0);
	//cin.tie(0),cout.tie(0);
	
	double r,a,b,h;
	cin>>r>>a>>b>>h;
	
	if(2*r<=b)
	{
		puts("Drop");
	}
	else
	{
		double x = b/(a-b)*h;
		double xie = sqrt(b*b/4+x*x);
		double l = 2*r*xie/b;
		puts("Stuck");
		printf("%.9lf\n",l-x);
	}
	
	return 0;
}	

F

做过铁签到

vector<int>no;
 
signed main()
{
    //ios::sync_with_stdio(0);
    //cin.tie(0),cout.tie(0);
     
    no.push_back(1);
    no.push_back(2);
    no.push_back(4);
    no.push_back(5);
    no.push_back(7);
    no.push_back(8);
    rep(i,11,98)
    {
        int ge = i%10;
        int shi = i/10;
         
        if(((ge+shi) % 3 !=0) && (ge%3) !=0 && (shi%3) != 0 )
            no.push_back(i);
    }
         
    int t = read();    
    while(t--)
    {
        ll l = read(),r = read();
        if(l >= 100) out(r-l+1);
        else
        {
            ll ans = r - l + 1;
            for(auto x : no)
            {
                if(x >= l && x<=r) ans--;
            }
            out(ans);
        }
    }
     
    return 0;
}	

k

int b[1010];
int n;
double fo[1010];

double dod(int x,int y)
{
    return fo[abs(x-y)];
}

void solve()
{
    rep(i,0,n-1)
        rep(j,i+1,n-1)
            if(dod(i,b[i]) + dod(j,b[j]) > dod(i,b[j]) + dod(j,b[i]))
               swap(b[i],b[j]);
}

signed main()
{
    IOS;
    //inout.txt;
    
    rep(i,1,1010)
    {
        fo[i] = sqrt(i);
    }

    int t;
    cin>>t;
    while(t--)
    {
        cin>>n;
        rep(i,0,n-1)
            cin>>b[i];

        sort(b,b+n);
        rep(i,1,15) solve();
        rep(i,0,n-2)
        {
            cout<<b[i]<<" ";
        }
        cout<<b[n-1]<<'\n';
        
    }

    return 0;
}

I

int qmi(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)res=(LL)res*a%M;
        a=(LL)a*a%M;
        b>>=1;
    }
    return res;
}
int a[N],cnt1[N],s1[N],cnt2[N],s2[N],inv[N],n,f;
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i],inv[i]=qmi(i,M-2);
    for(int i=n;i>=0;i--)
        for(int j=n;j>=0;j--)
        {
            if(i==j&&i&&j)continue;
            if(a[i]>a[j])
            {
                f=cnt1[i]?(1+(LL)inv[cnt1[i]]*s1[i])%M:1;
                cnt2[j]++,s2[j]=(s2[j]+f)%M;
            }
            else
            {
                f=cnt2[j]?(1+(LL)inv[cnt2[j]]*s2[j])%M:1;
                cnt1[i]++,s1[i]=(s1[i]+f)%M;
            }
        }
 
    cout<<(f-1+M)%M<<"\n";
    return 0;
}

J

struct node{
    int u,v,w;
    bool f;
}tree[N*4];
  
node p_up(node l,node r,int cost)
{
    node ans;
    ans.f= l.f&r.f;
    if(l.u+cost > r.v) ans.f=0;
    ans.u=max(r.u,l.u+cost+r.w);
    ans.v=min(l.v,r.v-cost-l.w);
    ans.w=l.w+r.w+cost;
    return ans;
}
  
void build(int rt,int l,int r)
{
    if(l==r)
    {
        tree[rt]={u[l],v[l],0,true};
        return ;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    tree[rt]=p_up(tree[ls],tree[rs],cost[mid]);
}
  
void update(int rt,int l,int r,int x)
{
    if(l==r)
    {
        tree[rt]={u[l],v[l],0,true};
        return ;
    }
    int mid=(l+r)>>1;
    if(x<=mid)   update(ls,l,mid,x);
    else update(rs,mid+1,r,x);
    tree[rt]=p_up(tree[ls],tree[rs],cost[mid]);
}
  
node query(int rt,int l,int r,int L,int R)
{
     if(L<=l&&r<=R)
        return tree[rt];
    int mid = (l+r)>>1;
    if(R<=mid)
        return query(ls,l,mid,L,R);
    else if(L>mid)
        return query(rs,mid+1,r,L,R);
    else
        return p_up(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R),cost[mid]);
}
  
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            scanf("%d",&u[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&v[i]);
        for(int i=1;i<n;i++)
            scanf("%d",&cost[i]);
        build(1,1,n);
        int q;
        cin>>q;
        while(q--)
        {
            int op;cin>>op;
            if(op==0)
            {
                int l,r;
                scanf("%d%d",&l,&r);
                node ans = query(1,1,n,l,r);
                if(ans.f)    puts("Yes");
                else    puts("No");
            }
            else if(op==1)
            {
                int pos;
                scanf("%d",&pos);
                scanf("%d",&cost[pos]);
                update(1,1,n,pos);
            }
            else
            {
                int pos;
                scanf("%d",&pos);
                scanf("%d%d",&u[pos],&v[pos]);
                update(1,1,n,pos);
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值