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

传送门

题意:

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

思路:

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


发布了158 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44091178/article/details/104657898