题意:给你四个数,要你将他们平均分给两个人,看能不能平均分给两个人
思路:挺简单的,就先看他们的总和是不是偶数,不是肯定不行,是的话再进行判断,因为只有两种分配方式2和2,1和3,第一个种就选第一个数,看有没有数和他加起来等于总和的一半,第二个就是看有没有一个数等于总和的一半(刚开始没进入状态wa了好几发)
代码:
void solve() // 22 31
{
int sum = 0;
for (int i = 1; i <= 4; i++)
cin >> a[i], sum += a[i];
if (sum & 1)
{
cout << "NO" << endl;
return;
}
for (int i = 2; i <= 4; i++)
{
if (a[1] + a[i] == sum / 2)
{
cout << "YES" << endl;
return;
}
}
for (int i = 1; i <= 4; i++)
if (a[i] == sum / 2)
{
cout << "YES" << endl;
return;
}
cout << "NO" << endl;
}
题意:给你一个长度为n的大整数(以字符串的形式),你最多可以对他进行k次操作,每次操作是你可以将他的任意一位换成0~9的任意数字,但是不能让他有前导0,请你输出让他最小的整数
思路:其实就是贪心,再特判只有一位的时候以及k等于0的时候,如果k不等于0,分两种情况,第一位是1的话,就向后看将他的非0的那一位进行操作最多k次,将他变成0,如果第一位不是1 ,就将第一位变成1,k--,再进行上述的操作即可
代码:
void solve() //
{
int n, k;
cin >> n >> k; // 尽量让小的数占据高位
string s;
cin >> s;
if (k == 0)
{
cout << s << endl;
return;
}
if (s.size() == 1)
{
cout << 0 << endl;
return;
}
if (s[0] == '1')
{
for (int i = 1; i < s.size(); i++)
{
if (k == 0)
break;
if (s[i] != '0')
s[i] = '0', k--;
}
}
else
{
s[0] = '1';
k--;
for (int i = 1; i < s.size(); i++)
{
if (k == 0)
break;
if (s[i] != '0')
s[i] = '0', k--;
}
}
cout << s << endl;
}
题意:给你n个点,m条边,然后要在边上插入一个多米诺骨牌(有两个部分,每个部分都有相应的点数),每个点被指向点数必须相同,要求你求出最多可以给多少条边加上多米诺骨牌
思路:数据挺小的,容易找规律发现,如果顶点小于等于6的话,直接让每个顶点的下标被指向相应的点数就行,所以直接输出m就行,再特判一下七个点0条边的情况,顶点数大于7的话说明肯定是有两个点是重合的,但是两个重合的点是不能存在多条边连到另外一个点的,所以只要找出这样的边的数量,再将其删去,其他的都可以按照上述的操作把所有的边都加上多米诺骨牌
代码:
void solve() // 在图上放多米诺骨牌,看最多可以放多少个,每个指向同一顶点的半部分上的点都得相同
{
cin >> n >> m;
int sum = 0;
for (int i = 1; i <= m; i++)
{
cin >> a[i] >> b[i];
flag[a[i]][b[i]] = flag[b[i]][a[i]] = 1;
if (a[i] <= 6 && b[i] <= 6)
sum++;
}
if (m == 0)
{
cout << 0 << endl;
return;
}
if (n <= 6)
{
cout << m << endl;
return; // 顶点数小于6,直接让顶点的标号作为指向它的点数即可
}
else // 多于6个点
{ // 由于最多有6个顶点,如果出现了第7个顶点,那么就说明肯定有两个点是相同的,而这两相同的顶点是不能连同一条边的,所以可以直接记录有两个相同的点连同一条边的,让从m中删掉即可
int cnt = 0x3f3f3f3f;
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++) // 由于多出点肯定是和之前的某个点重合的,所以可以直接将j看做是和i重合的点
{
int res = 0;
for (int k = 1; k <= n; k++)
if (flag[i][k] && flag[j][k])
res++; // 记录可以删除的边
cnt = min(cnt, res);
}
}
cout << m - cnt << endl;
}
}
题意:给你n个人会的算法值和他们的能力值,要你求出所有能组队的队伍的最大能力值,能组队的队伍指的就是队伍中有两个及其以上的人是最厉害的(也就是这个队伍中至少有两个人的算法值是最大的)(一个人x比另外一个人y厉害指的是:x&y==y)
思路:其实就是枚举即可,先预处理出每个算法值出现的次数,再枚举每个人当他所在组的父亲(算法值最大的),只有至少存在一个和他算法值相同的情况才,他才能作为组中最大的,再用一个数组标记他被某个组选中了的(防止重复算),再在处理后将原来的算法值出现次数处理就行
tips:==判断符号是比位运算的优先级要高的,这就说明,在没有括号的情况下,优先执行==,例如a[i]&a[j]==a[j]这个程序的执行是先执行a[j]==a[j]然后返回1,再让a[i]和1做按位与,正确的应该是(a[i]&a[j])==a[j]
代码:
#define int long long
const int N = 7e3 + 10; // 只有所知道的算法是完全相同的才能放到一组,再求他们的最大能值
struct node
{
int a, b;
} ans[N];
int father[N];
int temp[N]; // 处理每个人可能组队的最大值
int n; // 这个可以组队的意思是,一个组中只有一个人是最大的,那么这个组就不能成立,所以可以处理出每个人的最大最大组队的值,再全加起来
// 看一个数组确定某个人是否已经被某个人选中变成一组了
void solve() // 其实按照这个比较,一个人比另外一个人强大就是看他们进行与运算怎么样,a[i]&a[j]==a[j]说明a[i]比a[j]强大
{
cin >> n;
unordered_map<int, int> mp; // 记录出现的次数
for (int i = 1; i <= n; i++)
cin >> ans[i].a, mp[ans[i].a]++;
for (int i = 1; i <= n; i++)
cin >> ans[i].b;
for (int i = 1; i <= n; i++)
{
int now = ans[i].a;
if (mp[ans[i].a] < 2)
continue; /// 如果这个数出现的次数小于2,说明如果和他组队找不到和他一样的(默认选取的这个数最大),直接跳过
for (int j = 1; j <= n; j++)
if ((father[j] == 0 || father[j] == i) && ((now & ans[j].a) == ans[j].a)) // 如果这个数还没有进入某个人的组,或者已经是这个组的了,同时他要比他的父亲小,才能加到这个组中
father[j] = i, temp[i] += ans[j].b; // 把这个数加到这个组中,就是将他的父节点标记
mp[ans[i].a] = -1; // 说明这个数已经被选做一次父亲了,所以防止重复,归零
}
int sum = 0;
for (int i = 1; i <= n; i++)
sum += temp[i]; // 加上选每个数为父节点所能组成的组的最大值即可
cout << sum << endl;
}