思路:这个题看上去是一个贪心, 但是这个贪心显然是错的. 事实上这道题目很简单, 先判断1个是否可以, 然后判断2个是否可以. 之后找到最小的k
(k > 2)k(k>2),
使得(m - k) mod 6 =
0(m?k)mod6=0即可.
证明如下: 3n(n-1)+1 =
6(n*(n-1)/2)+13n(n?1)+1=6(n?(n?1)/2)+1,
注意到n*(n-1)/2n?(n?1)/2是三角形数,
任意一个自然数最多只需要3个三角形数即可表示. 枚举需要kk个,
那么显然m=6(km=6(k个三角形数的和)+k)+k,
由于k \ge 3k≥3,
只要m-km?k是6的倍数就一定是有解的.
事实上, 打个表应该也能发现规律.
两边向中间找扫描的时候落了等号错了好多次,忘了数相等的时候也可以,最后找最小的k,直接取余就行,最少是从3开始的。
#include <bits/stdc++.h> #pragma comment(linker, "/STACK:1024000000,1024000000") #define INF 9999999999 #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef unsigned long long llu; typedef long long ll; const int maxd=18258+5; ///========================= int s[maxd]; int m; void table() { s[0]=0; for(int i=1;i<maxd;i++) s[i]=3*i*(i-1)+1; } bool ok1(int x) { int pos=lower_bound(s,s+maxd,x)-s; if(s[pos]==x) return true; return false; } bool ok2(int x) { if((x-2)%6) return false; int l=1,r=maxd-1; while(l<=r) { if(s[l]+s[r]<x) l++; else if(s[l]+s[r]>x) r--; else return true; } return false; } int main() { int kase; // freopen("1.txt","r",stdin); table(); scanf("%d",&kase); while(kase--) { scanf("%d",&m); if(ok1(m)) printf("1\n"); else if(ok2(m)) printf("2\n"); else { // for(int k=3;k<=m;k++) // if((m-k)%6==0) // { // printf("%d\n",k); // break; // } printf("%d\n",(m-3)%6+3); } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-10 06:10:41