NC200190 矩阵消除游戏
题目链接
关键点:
1、因为无论行和列的选择会相互影响,所以不能直接利用贪心,要将行列分开选。
2、先选行,因为最大有20行,利用二进制的01来表示当前所选的行,1表示选择该行
3、接下来跟据所选的行对原数组进行选中的行的值求和,对于没选中的行,将其加入列数组里,因为选择的行在算列时,已经被删除。
4、将列数组进行排序,并倒着(从小到大排序)选择大的求和
5、细节:如果当前可以选的k大于行数或者列数(n和m),那么直接输出所有数的和
6、细节:算好选择行数时,要判断剩余给列选择的数是否大于0
完整代码:
# include <iostream>
# include <algorithm>
# include <cstring>
using namespace std;
int n, m, k;
int a[20][20];
int lie[20];
int cnt, ans;
int calc(int x)
{
int total=0;
cnt=0;
for (int i=1; i<=n; i++)
{
if ((x>>(i-1))&1==1)
{
for (int j=1; j<=m ; j++)
total+=a[i][j];
cnt++;
}
else
{
for (int j=1; j<=m; j++)
{
lie[j]+=a[i][j];
}
}
}
return total;
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
int sum=0;
for (int i=1; i<=n; i++)
{
for (int j=1; j<=m; j++)
{
scanf("%d", &a[i][j]);
sum+=a[i][j];
}
}
if (k>=n||k>=m)
{
cout<<sum<<endl;
return 0;
}
for (int i=0; i<=(1<<n)-1; i++)
{
memset(lie, 0, sizeof(lie));
sum = calc(i);
int res = k-cnt;
if (res<0)
continue;
sort(lie+1, lie+1+m);
for (int j=m; j>=1&&res; res--,j--)
{
sum+=lie[j];
}
ans = max(ans, sum);
}
cout<<ans;
return 0;
}
NC23036 华华听月月唱歌
题目链接
关键点:
1、将区间数据按照第一关键字:起始点(从小到大),第二关键字:结尾(从大到小)排序
2、设出初始的l,r值为1,之后进行更新,如果当前的起始点会小于等于l,那么更新r的最大值,如果不满足,那么总数加1,l=r+1,再次判断当前结点
3、因为这样判断会把最后一个数的个数给忽略,所以初始值的个数从1开始
完整代码:
# include <iostream>
# include <algorithm>
# include <cstdio>
# include <set>
using namespace std;
int n, m;
struct ty{
int start;
int end;
}t[100000+10], t2[100000+10];
set<int>s;
bool cmp(ty t1, ty t2)
{
if (t1.start!=t2.start)
return t1.start<t2.start;
else
return t1.end>t2.end;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i=1; i<=m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
t[i].start = x;
t[i].end = y;
}
sort(t+1, t+1+m, cmp);
int l = 1;
int r = 1;
if (l!=1)
{
cout<<"-1";
return 0;
}
int total=1;
for (int i=1; i<=m; i++)
{
if (t[i].start<=l)
r = max(r, t[i].end);
else
{
total++;
l = r+1;
if (t[i].start<=l)
r = max(t[i].end, r);
else
{
cout<<"-1";
return 0;
}
}
if (r>=n)
break;
}
if (r>=n)
cout<<total;
else
cout<<"-1";
return 0;
}