zoukankan      html  css  js  c++  java
  • [luogu p1249] 最大乘积

    传送门

    最大乘积

    题目描述

    一个正整数一般可以分为几个互不相同的自然数的和,如 (3=1+2)(4=1+3)(5=1+4=2+3)(6=1+5=2+4)

    现在你的任务是将指定的正整数 (n) 分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。

    输入输出格式

    输入格式

    只一个正整数 (n),((3 leq n leq 10000))。

    输出格式

    第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。 第二行是最大的乘积。

    输入输出样例

    输入样例 #1

    10
    

    输出样例 #1

    2 3 5
    30
    

    分析

    此题的关键是抓住和同近积大的原理。
    和同近积大:两个数的和一定,差小,积大。
    也就是说,假设(a ge b),那么((a + 1) imes (b - 1) < a imes b)

    简证:((a + 1) imes (b - 1) = a imes b + b - a - 1),而既然(a ge b),那么(b - a le 0)。最后这个算式还有个减一,因此((a + 1) imes (b - 1) < a imes b)

    我们考虑在两个的和同近积大原理上进行扩展。因为此题要求所有数字互不相同,我们也想要尽可能多的因数,然后他们还越接近越好。于是如此,我们就可以构造一个由2开始的自然数数列,然后一直求和,直到这个和大于了(n)

    为什么从(2)开始?如果从(1)开始的话,(1)浪费了这个数和的一块,却对整体的积一点用都没用。血亏!

    但是此时和是大于(n)的,那么假设多出来的是(k)吧,那么此时就把值为(k)的那项移出去。此时得到的就是正确的数列——

    吗?

    • 不,你忘考虑了(k = 1)的情况。这种情况下的最优解是去掉开头的2,然后给末尾项加1。
    • 你还忘考虑了(n = 3,4)的情况,此时的解就是(n)本身。

    其实我有一个问题,就是上述解法是我根据不严谨的思路推出来的,我还没有想好一种严格证明的方案,有小伙伴能告诉我吗?我感激不尽。

    哦对了,这道题还需要高精度哦,别忘了,(n le 10000),不开高精见祖宗呢。

    代码

    本代码采用了高精模板。link

    /*
     * @Author: crab-in-the-northeast 
     * @Date: 2020-04-02 00:58:54 
     * @Last Modified by: crab-in-the-northeast
     * @Last Modified time: 2020-04-02 01:10:27
     */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cassert>
    #include <vector>
    
    int max(int a,int b) {
    	return a > b ? a : b;
    }
    
    struct ubigint {
    	typedef unsigned long long ull;
    
    	static const int base = 100000000;
    	static const int width = 8;
    	
    	std :: vector<int> s;
    
    	ubigint& clear_zero() {
    		while(!s.back() && s.size() > 1) s.pop_back();
    		return *this;
    	}
    	
    	ubigint(ull num = 0) {*this = num;}
    	ubigint(std :: string str) {*this = str;}
    
    	ubigint& operator = (ull num) {
    		s.clear();
    		do {
    			s.push_back(num % base);
    			num /= base;
    		}while(num);
    		return *this;
    	}
    
    	ubigint& operator = (const std :: string& str) {
    		s.clear();
    		int x;
    		int len = (str.length() - 1) / width + 1;
    		for(int i = 0; i < len; i++) {
    			int endidx = str.length() - i * width;
    			int startidx = max(0, endidx - width);
    			int x;
    			sscanf(str.substr(startidx, endidx - startidx).c_str(), "%d", &x);
    			s.push_back(x);
    		}
    		return (*this).clear_zero();
    	}
    
        bool operator < (const ubigint& b) const {
            if(s.size() != b.s.size()) return s.size() < b.s.size();
            for(int i = s.size() - 1; i >= 0; i--)
                if(s[i] != b.s[i])
                    return s[i] < b.s[i];
            return false;
        }
        bool operator > (const ubigint& b) const {return b < *this; }
        bool operator <= (const ubigint& b) const {return !(b < *this);}
        bool operator >= (const ubigint& b) const {return !(*this < b);}
        bool operator == (const ubigint& b) const {return !(b < *this) && !(b > *this);}
        bool operator != (const ubigint& b) const {return b < *this || *this < b;}
    
        ubigint operator + (const ubigint& b) const {
            ubigint res;
            res.s.clear();
            for(int i = 0, x = 0; x || i < s.size() || i < b.s.size(); i++, x /= base) {
                if(i < s.size()) x += s[i];
                if(i < b.s.size()) x += b.s[i];
                res.s.push_back(x % base);
            }
            return res.clear_zero();
        }
    
    	ubigint operator - (const ubigint& b) const {
    		assert(*this >= b);
    		ubigint res;
    		res.s.clear();
    		for(int i = 0, last = 0;last || i < s.size() || i < b.s.size();i++) {
    			int x = s[i] + last;
    			if(i < b.s.size()) x -= b.s[i];
    			if(x < 0) {
    				last = -1;
    				x += base;
    			}else last = 0;
    			res.s.push_back(x);
    		}
    		return res.clear_zero();
    	}
    
    	ubigint operator * (const ubigint& b) const {
    		std :: vector<ull> tmp(s.size() + b.s.size(),0);
    		ubigint res;
    		res.s.clear();
    		for(int i = 0; i < s.size(); i++)
    			for(int j = 0; j < b.s.size(); j++)
    				tmp[i + j] += ull(s[i]) * b.s[j];
    		
            ull last = 0;
    		for(int i = 0; last || i < tmp.size(); i++) {
    			ull x = tmp[i] + last;
    			res.s.push_back(x % base);
    			last = x / base;
    		}
    		return res.clear_zero();
    	}
    
    	int midsearch(const ubigint& b, const ubigint& m) const {
    		int l = 0, r = base - 1;
    		while(1) {
    			int mid = l + r >> 1;
    			if(b * mid <= m && b * (mid + 1) > m) return mid;
    			if(b * mid <= m) l = mid;
    			else r = mid;
    		}
    	}
    
    	ubigint operator / (const ubigint& b) const {
    		assert(b > 0);
    		ubigint res = *this, mod;
    		for(int i = s.size() - 1; i >= 0; i--) {
    			mod = mod * base + s[i];
    			res.s[i] = midsearch(b, mod);
    			mod -= b * res.s[i];
    		}
    		return res.clear_zero();
    	}
    
    	ubigint operator % (const ubigint& b) const {
    		assert(b > 0);
    		ubigint res = *this, mod;
    		for(int i = s.size() - 1; i >= 0; i--) {
    			mod = mod * base + s[i];
    			res.s[i] = midsearch(b, mod);
    			mod -= b * res.s[i];
    		}
    		return mod.clear_zero();
    	}
    
    	ubigint& operator += (const ubigint& b) {*this = *this + b; return *this;}
    	ubigint& operator -= (const ubigint& b) {*this = *this - b; return *this;}
    	ubigint& operator *= (const ubigint& b) {*this = *this * b; return *this;}
    	ubigint& operator /= (const ubigint& b) {*this = *this / b; return *this;}
    	ubigint& operator %= (const ubigint& b) {*this = *this % b; return *this;}
    	
    
    	friend std :: istream& operator >> (std :: istream& in, ubigint& x) {
    		std :: string str;
    		if(!(in >> str)) return in;
    		x = str;
    		return in;
    	}
    
    	friend std :: ostream& operator << (std :: ostream& out, ubigint x) {
    		out << x.s.back();
    		for(int i = x.s.size() - 2; i >= 0; i--) {
    			char buf[20];
    			sprintf(buf, "%08d", x.s[i]);
    			for(int j = 0; j < strlen(buf); j++)
    				out << buf[j];
    		}
    		return out;
    	}
    };
    
    int main() {
        int n;
        std :: cin >> n;
    	int sum = 0, to;
        if(n <= 4) {
            std :: cout << n << std :: endl << n << std :: endl;
            return 0;
        }
        for(int i = 2; sum <= n; i++) {
            sum += i;
            to = i;
        }
        ubigint ans = 1;
        for(int i = 2; i <= to; i++) {
    		if(sum - n == 1)  {
    			if(i == 2) continue;
    			if(i == to) {
    				std :: cout << i + 1 << ' ';
    				ans *= (i + 1);
    				break;
    			}
    		}
    		if(i != sum - n) {
                std :: cout << i << ' ';
                ans *= i;
            }
        }
        std :: cout << std :: endl << ans << std :: endl;
        return 0;
    }
    

    评测结果

    • AC 100:R32389140(本代码虽然AC了数据,但解法有纰漏,没有特判多出来的是(1)的情况。)
    • AC 100:R32389231
  • 相关阅读:
    GAIN: Gradient Augmented Inpainting Network for Irregular Holes
    Python+Selenium实现对浏览器的自动操作
    python 中的内置类属性__name__和__doc__
    Python 装饰器
    Free-Form Image Inpainting with Gated Convolution
    解决ubuntu安装软件has install-snap change in progress错误
    Image Inpainting for Irregular Holes Using Partial Convolutions
    理解卷积
    Hive中分区表修复问题
    B2B、B2C、C2C、O2O分别是什么意思?
  • 原文地址:https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p1249.html
Copyright © 2011-2022 走看看