CodeForces - 1305 E. Kuroni and the Score Distribution(思维 详解)

33 篇文章 0 订阅
24 篇文章 0 订阅

传送门

题意:

给两个整数n,m
让输出一个长度为n的数组,满足 1 ≤ i < j < k ≤ n 1≤i<j<k≤n 1i<j<kn
a i + a j = a k a_i+a_j=a_k ai+aj=ak的组数为m组

思路:

考虑如何让符合的三元组数更多,即1,2,3,4,5,6…这样的时候, a [ i ] = i a[i]=i a[i]=i
那每个位置能贡献几组满足题意的三元组呢
计算发现他们的贡献为
0,0,1,2,4,6,9,12…即 ( i − 1 ) / 2 (i-1)/2 i1/2
意思就是我每增加一个数,它都能贡献 ( i − 1 ) / 2 (i-1)/2 i1/2
做法: c n t cnt cnt记录当前已经有多少组了,每次 c n t + = ( i − 1 ) / 2 cnt+=(i-1)/2 cnt+=(i1)/2
然后考虑边界,在增加一个数时,发现 c n t + ( i − 1 ) / 2 > m cnt+(i-1)/2>m cnt+(i1)/2>m了,意思就是这个位置不能是 i i i了,那应该是多少呢?我们考虑还需要几组,显然还需要 p = m − c n t p=m-cnt p=mcnt组,那添加哪个数刚好增加p组呢
往前找 2 ∗ p 2*p 2p个数,比如 p = 5 p=5 p=5,当前要在 i = 50 i=50 i=50的位置添加数
40,41,42,43,44,
45,46,47,48,49,我们发现这 2 ∗ p 2*p 2p个数,可以构成p对和都是 40 + 49 = 41 + 48 = . . . . . . = 89 40+49=41+48=......=89 40+49=41+48=......=89
a [ 50 ] = 89 a[50]=89 a[50]=89,是不是就可以增加 p p p
所以 a [ i ] a[i] a[i]应该等于 i − 1 + i − 2 ∗ p i-1+i-2*p i1+i2p
这样 m m m组已经完成了,如何数组 n n n还没有填满,后面的就随便填,保证不会再组成 a i + a j = a k a_i+a_j=a_k ai+aj=ak即可,因为 n n n总共才 5000 5000 5000,选一个大点的数开始,每次直接增加 5050 5050 5050,肯定不可能再组成
特判: 如果 c n t ! = m cnt!=m cnt!=m,说明数组填满之后还不够,输出 − 1 -1 1

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <map>
#include <queue>
#include <set>
#include <stack>
typedef long long ll;
#define PII make_pair
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int MAXN=2e5+50;
const int inf=0x3f3f3f3f;
const int M=5000*4;
int a[5050];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int cnt=0;
    int flag=0;
    int k=0;
    for(int i=1;i<=n;i++){
    	if(flag==1){//已经够m个了
    		a[i]=5e8+k;
    		k+=5050;
    		continue;
    	}
    	if(cnt+(i-1)/2<=m){
    		a[i]=i;
    		cnt+=(i-1)/2;
    	}
    	else {
    		int p=m-cnt;
    		cnt+=p;
    		a[i]=i-1+i-2*p;
    		flag=1;//刚好m个
    	}

    }
    if(cnt!=m)printf("-1\n");
    else {
    	for(int i=1;i<=n;i++)
    		printf("%d%c",a[i],i==n?'\n':' ');
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值