标签:
思路:这个题看上去是一个贪心, 但是这个贪心显然是错的. 事实上这道题目很简单, 先判断1个是否可以, 然后判断2个是否可以. 之后找到最小的k(k>2), 使得(m?k)mod6=0即可.
证明如下: 3n(n?1)+1=6(n?(n?1)/2)+1, 注意到n?(n?1)/2是三角形数, 任意一个自然数最多只需要3个三角形数即可表示. 枚举需要k个, 那么显然m=6(k个三角形数的和)+k, 由于k≥3, 只要m?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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/whoisvip/article/details/47126707