给一个n x m的矩阵,由’#‘和’.'构成,分别代表黑色和白色,现在你可以任选若干行和若干列将其涂成红色,问有多少种涂法使最终只有k个黑色。
#include
#include
#include
#include
using namespace std;
char a[10][10];
long long int n, m, k;
long long num=0, ans=0;
int used[10] = { 0 };
void dfs(int r, int c, int sum)//行 列 涂去的黑色
{
int add = 0;
if (r == n && c == m)
{
if (num - sum == k)
ans++;
return;
}
if (r == n)
{
for (int i = 0; i < n; i++)
{
if (a[i][c] == '#' && (!used[i]))
{
add++;
}
}
dfs(r, c + 1, sum + add);
dfs(r, c + 1, sum);
}
else
{
for (int i = 0; i < m; i++)
{
if (a[r][i] == '#')
{
add++;
}
}
used[r] = 1;
dfs(r + 1, c, sum + add);
used[r] = 0;
dfs(r + 1, c, sum);
}
}
int main()
{
cin >> n >> m >> k;
for (int i = 0; i < n; i++)
cin >> a[i];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (a[i][j] == '#')
num++;
}
}
dfs(0, 0, 0);
cout << ans << endl;
}
现在有一排数字,现在要将这排数字按顺序放入一个圈,每个数字在插入圈时,他的权值就是相邻两个数字中小的那个,第一个插入的人权值为0,问总权值是多少。
既然要让权值最大,那必然要让大的值先插入,否则会被相邻的小的值影响,导致不能贡献权值。所以要先排序。又因为是一个圈,左右两边都能贡献权值,所以除了最大的数只能贡献一次,剩余的数都可以贡献两次。注意判断数量的奇偶。
#include
#include
#include
#include
using namespace std;
long long int m,t;
long long int a[200005];
int main()
{
cin >> t;
for (int i = 1; i <= t; i++)
{
cin >> a[i];
}
sort(a + 1, a + 1 + t);
m = a[t];
int j = t - 1;
for (int i = (t - 2) / 2; i > 0; i--)
{
m += 2 * a[j--];
}
if (t % 2 == 1)
{
m += a[j];
}
cout << m;
}
求从n个数选出k个数的乘积最大值结果再取模1e9+7。
对于多个数的乘积想要结果最大,在满足绝对值最大的情况下要满足包含偶数个负数。
对于所选的数是奇数时,首先就取一个最大正数,接下来就是俩个正数积和俩个负数积取最大。
当正数数量为0,且选择数量为奇数时结果一定为负,这时要想结果最大的话就要取k个绝对值最小的数。
#include
#include
#include
#include
using namespace std;
long long int mod = 1e9 + 7;
long long int n,m;
long long int a[200005];
bool cmp(int x, int y)
{
return abs(x) < abs(y);
}
int main()
{
int pn=0 ,nn = 0;
//pn正数,nn负数;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (a[i] >= 0)
pn++;
else
nn++;
}
int l=1, r=n;//左右逼近
long long ans = 1;
if (!pn && m % 2 == 1)//结果必定为负数
{
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= m; i++)
ans = a[i] * ans % mod;
}
else
{
sort(a + 1, a + 1 + n, greater< int >());
内置类型的由大到小排序
while (m)
{
if (m % 2 == 1)//为奇数就乘大的正数
{
ans = ans * a[l] % mod;
l++, m--;
}
else
{
if (a[l] * a[l + 1] >= a[r] * a[r - 1])
//两正数乘起来比负数大
{
ans = ans * a[l] % mod * a[l + 1] % mod;
l += 2,m -= 2;
}
else
{
ans = ans * a[r - 1] % mod * a[r] % mod;
r -= 2,m -= 2;
}
}
}
}
//防止出现负数,故再加mod再取余数
cout << (ans % mod + mod) % mod << endl;
}
给你一棵树,节点为1到n,取若干连续编号的节点,求出其连通分量,问所有连续段的连通分量之和。
直接算不好算所以先算一开始一条边都没有的时候答案是多少,然后每加入一个边,就把含他的s的数量去掉。
#include
#include
#include
#include
using namespace std;
int main()
{
long long n, l, r,sum=0;
cin >> n;
for (int i = 1; i <= n; i++)
{
sum += i * (n - i + 1);
}
for (int i = 1; i < n; i++)
{
cin >> l >> r;
if (l > r)
swap(l, r);
sum -= l * (n - r + 1);
}
cout << sum << endl;
}