一、数字矩阵
题目链接
给定一个 n×m 的整数矩阵,其中第 i 行第 j 列的元素为 aij。
你可以进行任意多次如下操作:
选择矩阵中的两个相邻元素,将它们均乘以 −1。
同一个元素可以被选中多次。
你需要通过上述操作,使得矩阵中所有元素的和尽可能大。
计算并输出这个和的最大可能值。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含两个整数 n,m。
接下来 n 行,每行包含 m 个整数,表示整个矩阵,其中第 i 行第 j 列的数为 aij。
输出格式
每组数据输出一行结果,表示矩阵的所有元素的最大可能和。
数据范围
1≤T≤100,
2≤n,m≤10,
−100≤aij≤100
输入样例:
2
2 2
-1 1
1 1
3 4
0 -1 -2 -3
-1 -2 -3 -4
-2 -3 -4 -5
输出样例:
2
30
找规律一题,假设有b个负数,如果b是偶数,那么都可以变成正的,如果b是奇数,那么至少会有一个负数
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m,cnt=0,x,sum=0,minw=1e8;
cin>>n>>m;
for(int i=0;i<n*m;i++)
{
cin>>x;
sum+=abs(x);
if(x<0)
cnt++;
if(abs(x)<minw)
minw=abs(x);
}
if(cnt%2)//如果负数是奇数的话
printf("%d\n",sum-=2*minw);
else printf("%d\n",sum);
}
return 0;
}
二、三元牛异或(贪心)
如果一个整数,其各个数位不包含 0,1,2 以外的数字,则称这个数为三元数。
例如,1022,11,21,2002 都是三元数。
给定一个可能很长的三元数 x,其首位数字(最左边那位)保证为 2,其他位数字为 0 或 1 或 2。
我们规定,两个长度为 n 的三元数 a 和 b 可以通过三元异或运算 ⊙ 得到另一个长度为 n 的三元数 c。
设 ai,bi,ci 分别表示 a,b,c 的第 i 位的数字,则 ci=(ai+bi)mod3。
例如,10222 ⊙ 11021=21210。
你的任务是对于每个给定的 x,求出可以满足 a ⊙ b=x,并且 max(a,b) 尽可能小的 a,b。
注意,a,b 都必须是 n 位三元数,且不含前导 0。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含整数 n,表示 x 的长度。
第二行包含一个长度为 n,首位为 2 的三元数 x。
输出格式
每组数据输出占两行,分别包含数 a 和数 b。
如果答案不唯一,则输出任意合理答案均可。
数据范围
1≤T≤104,
1≤n≤5×104,
同一测试点所有 n 的和不超过 5×104。
输入样例:
4
5
22222
5
21211
1
2
9
220222021
输出样例:
11111
11111
11000
10211
1
1
110111011
110111010
1.三进制的异或运算,别名—不进位的加法。
2.贪心,它可以把每一个集合部分找出最优解,而dp的不行
3.这个时候是分情况的,我们规定a>b,且a要尽可能的小,所以这个时候,就要分a是否已经大于b的情况
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
string x;
cin>>n>>x;
string a,b;
bool flag=false;
for(auto c:x)
{
if(c=='0') a+='0',b+='0';
else if(c=='1')
{
if(flag)//说明a一定大于b
a+='0',b+='1';
else a+='1',b+='0',flag=true;//这个时候就保证了a>b
}
else if(c=='2')
{
if(flag)a+='0',b+='2';
else a+='1',b+='1';
}
}
cout<<a<<endl<<b<<endl;
}
return 0;
}
三、最小的值
给定两个长度为 n 的 01 数组 a1,a2,…,an 和 b1,b2,…,bn。
请你构造一个长度为 n 的正整数数组 p1,p2,…,pn。
要求 ∑i=1nai×pi>∑i=1nbi×pi 成立。
此外,maxi=1npi 需要尽可能小。
输出最小可能值。
输入格式
第一行包含整数 n。
第二行包含 n 个整数 a1,a2,…,an。
第三行包含 n 个整数 b1,b2,…,bn。
输出格式
输出 maxi=1npi 的最小可能值。
如果不存在满足条件的数组 p,则输出 −1。
数据范围
1≤n≤100,
0≤ai,bi≤1
输入样例1:
5
1 1 1 0 0
0 1 1 1 1
输出样例1:
3
输入样例2:
3
0 0 0
0 0 0
输出样例2:
-1
输入样例3:
4
1 1 1 1
1 1 1 1
输出样例3:
-1
输入样例4:
9
1 0 0 0 0 0 0 0 1
0 1 1 0 1 1 1 1 0
输出样例4:
4
这是一个贪心题,因为a数组,b数组只有0和1两种情况
当ai=bi时,pi可以取任意值,这里规定为1
当ai<bi时,pi也取1,有x个
在把以上两种情况统计之后,在来决定当ai>bi时的pi的值,有y个
yt>x,so t>=[x+1/y]upper,向上取整,平分会使最大值最小
ceil(a/b)=(a+b-1)/b
^上取整 …………^下取整
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N=110;
int a[N],b[N];
int main()
{
int n,x=0,y=0;
cin>>n;
for(int i=0;i<n;i++)cin>>a[i];
for(int i=0;i<n;i++)cin>>b[i];
for(int i=0;i<n;i++)
{
if(a[i]<b[i])
x++;
else if(a[i]>b[i])y++;
}
if(!y) puts("-1");
else cout<<(x+1+y-1)/y<<endl;
return 0;
}
四、字符串删减(双指针算法)
题目链接
给定一个由 n 个小写字母构成的字符串。
现在,需要删掉其中的一些字母,使得字符串中不存在连续三个或三个以上的 x。
请问,最少需要删掉多少个字母?
如果字符串本来就不存在连续的三个或三个以上 x,则无需删掉任何字母。
输入格式
第一行包含整数 n。
第二行包含一个长度为 n 的由小写字母构成的字符串。
输出格式
输出最少需要删掉的字母个数。
数据范围
3≤n≤100
输入样例1:
6
xxxiii
输出样例1:
1
输入样例2:
5
xxoxx
输出样例2:
0
输入样例3:
10
xxxxxxxxxx
输出样例3:
8
这一题是道经典的双指针算法
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int n;
string s;
cin>>n>>s;
int ans=0;
for(int i=0;i<n;i++)
{
if(s[i]!='x')continue;
int j=i+1;
while(j<n&&s[j]=='x')j++;
ans+=max(0,j-i-2);
i=j-1;
}
printf("%d\n",ans);
return 0;
}
五、移动石子
题目链接
一共有 n 个箱子排成一排,从左到右依次编号为 1∼n。
其中,第 i 号箱子中放有 ai 个石子。
现在,你可以进行最多 d 次操作。
每次操作可以将一个石子从一个箱子移动至另一个与其相邻的箱子里。
我们希望通过合理操作使得 1 号箱子内的石子数量尽可能大。
请问,这个最大可能值是多少?
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含两个整数 n 和 d。
第二行包含 n 个整数 a1,a2,…,an。
输出格式
每组数据输出一行结果,表示答案。
数据范围
1≤T≤100,
1≤n,d≤100,
0≤ai≤100
输入样例:
3
4 5
1 0 3 2
2 2
100 1
1 8
0
输出样例:
3
101
0
自己的做法
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N=110;
int a[N];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,d;
scanf("%d%d",&n,&d);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
if(n==1){printf("%d\n",a[0]);continue;}
for(int i=1;i<n;i++)
{
if(d>a[i]*i)
{
d-=a[i]*i;
a[0]+=a[i];
}
else {
d/=i;
a[0]+=d;
break;
}
}
printf("%d\n",a[0]);
}
return 0;
}
当然,做完之后看了y总的做法,就觉得他的方法真的很棒!
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N=110;
int a[N];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,d;
scanf("%d%d",&n,&d);
int res=0;
for(int i=0;i<n;i++)
{
int x;
scanf("%d",&x);
if(!i)res+=x;
else
{
int t=min(x,d/i);//看能移动几个
res+=t;
d-=t*i;
}
}
cout<<res<<endl;
}
return 0;
}
总结
于是这个星期的题就写完了!哦耶!