[英]Elevenagram Round H google kickstart
我一直在试图了解从Kickstart中圆形H 2019的解决问题的办法elevanagram https://codingcompetitions.withgoogle.com/kickstart/round/0000000000050edd/00000000001a286d
给定一个由1到9的数字组成的数字,您可以重新排列这些数字以创建一个可被11整除的数字吗?
由于数量可能很大,因此您会得到整数A1,A2,...,A9。 号码i中有i个数字,代表所有i。
输入:输入的第一行给出测试用例的数量,T。T行>跟随。 每行包含九个整数A1,A2,...,A9。
输出:对于每个测试用例,输出包含Case #x:y的一行,其中x是>测试用例编号(从1开始),如果数字可以重新排列以创建11的倍数,则y是YES。除此以外。
限制时间限制:每个测试集20秒。 内存限制:1GB。
对于所有i,测试集1(可见):0≤Ai≤20。
测试集2(隐藏):对于所有i,0≤Ai≤10 ^ 9。
问题分析表明:假设i的正数为Pi,i的负数为Ai-Pi。 然后,我们将具有以下三个方程式:
(1)∑ Pi =面值(sum(A)/ 2)
(2)Σi×(Pi-(Ai-Pi))%11 = 0
(3)0≤Pi≤Ai
为了解决这个问题,首先我们可以将每个数字的一半放在正数分区中(例如,Pi = Ai / 2,注意奇数),然后尝试调整每个Pi来满足等式(2)。 对于每个i,我们可以将其Pi从-Ai / 2调整为Ai / 2。
我们可以证明以下两个结论:
如果Ai≥10的数目至少为两个,则解必须存在。
这很容易证明。 我们只能将这两个数字从-5调整到5,每次调整将导致模数11的剩余值不同。因此,最终我们将得到0。
如果至少有三个Ai≥6,那么该解必须存在。
为了证明这一点,我们可以证明:
对于任何1≤i <j <k≤9,0≤r≤10,以下等式:
(1)(i * x1 + j * x2 + k * x3)%11 = r
(2)x1 + x2 + x3 = 0
(3)-3≤xi≤3
将有一个有效的解决方案。
为什么至少有2个数字的count> = 10或什至一个数字的count> = 20是正确的,所以解决方案总是存在的?对这两个都有简单的数学证明吗? 另外,我正在提交相同的问题。
#include <iostream>
#include <algorithm>
#include <fstream>
#include <vector>
#include <deque>
#include <assert.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <stdio.h>
#include <string.h>
#include <utility>
#include <math.h>
#include <bitset>
#include <iomanip>
#include <complex>
using namespace std;
#define rep(i, a, b) for (int i = (a), i##_end_ = (b); i < i##_end_; ++i)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
#define x first
#define y second
#define pb push_back
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(), (x).end()
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool smin(T &a, const T &b) { return a > b ? a = b : a; }
template<typename T> inline bool smax(T &a, const T &b) { return a < b ? a = b : a; }
typedef long long LL;
const int N = (int) 505, mod = (int) 0;
int cnt[10], dp[N][11], odp[N][11];
int main() {
int tc;
cin >> tc;
for (int tt = 1; tt <= tc; ++tt) {
cout << "Case #" << tt << ": ";
int sum = 0;
for (int j = 1; j < 10; ++j) {
cin >> cnt[j];
if (cnt[j] > 20) {
cnt[j] = 20 + (cnt[j] & 1);
}
sum += cnt[j];
}
memset(dp, 0, sizeof dp);
dp[0][0] = 1;
for (int j = 1; j < 10; ++j) {
memcpy(odp, dp, sizeof dp);
memset(dp, 0, sizeof dp);
for (int pick = 0; pick <= cnt[j]; ++pick) {
for (int lpick = 0; lpick + pick < N; ++lpick) {
for (int lmod = 0; lmod < 11; ++lmod) {
int nmod = (lmod + pick * j + (11 - j) * (cnt[j] - pick)) % 11;
dp[lpick + pick][nmod] |= odp[lpick][lmod];
}
}
}
}
if (dp[sum / 2][0]) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
}
我知道为什么所有计数都减少到最多20个,但是为什么我们还要循环处理残渣类呢? 为什么我们将残渣添加到实际获得的残渣中? 请帮助。我已经尝试了两天,但没有成功的逻辑。任何帮助如何去理解问题表示赞赏。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.