每日一题
目录
题目:平均
问题:有一个长度为 n 的数组(n 是 10 的倍数),每个数 ai 都是区间 [0, 9] 中的整数。小明发现数组里每种数出现的次数不太平均,而更改第 i 个数的代价为bi,他想更改若干个数的值使得这 10 种数出现的次数相等(都等于n/10),请问代价和最少为多少。
输入格式:
输入的第一行包含一个正整数 n 。
接下来 n 行,第 i 行包含两个整数 ai , bi ,用一个空格分隔。
样例:
10 1 1 1 2 1 3 2 4 2 5 2 6 3 7 3 8 3 9 4 10
输出:
27
思路:
我们不用管这个数是几,只需要看它的数量,多了就删,少了就跳过,不管。这里我直接建了二维数组,这样的话,只需要跑一次排序即可,比较方便
#include <bits/stdc++.h>
using namespace std; //分类讨论
int a[10][100000],len[10];
int main(){
long long ans=0,n,x,y;cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld %lld",&x,&y);
a[x][++len[x]]=y; //引入二维数组,和长度数组
}
for(int i=0;i<10;i++){
sort(a[i],a[i]+len[i]+1); //对每个一维数组排序,根据每个数组的长度
}
int tmp=n/10;
for(int i=0;i<10;i++){
for(int j=1;j<=len[i]-tmp;j++){ //不用管这个数是几,大于n/10就删就完了
ans+=a[i][j];
}
}
cout<<ans; //不要用int
}
问题:填充
有一个长度为 n 的 01 串,其中有一些位置标记为 ?,这些位置上可以任意填充 0 或者 1,请问如何填充这些位置使得这个 01 串中出现互不重叠的 00 和 11 子串最多,输出子串个数。
输入格式:
输入一行包含一个字符串。
1110?0
输出格式:
2
思路:
不用管?填什么,只要能凑出又一个00或11就行!!!(共3中情况)
?打头就直接ans++,i+=2
1?和0?直接ans++,i+=2
10和01 就i+=1; 11和00就ans++,i+=2
#include <bits/stdc++.h>
using namespace std; //分类讨论 模拟
int main(){
string s;cin>>s;
int ans=0,len=s.size();
for(int i=0;i<len;){
if(s[i]=='?')ans++,i+=2;
else if(s[i+1]!='?'){
if(s[i]==s[i+1]) ans++,i+=2;
else i+=1;
}else{
ans++;i+=2;
}
}
cout<<ans;
}
题目:三国游戏
小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵X, Y, Z (一开始可以认为都为 0 )。游戏有 n 个可能会发生的事件,每个事件之间相互独立且最多只会发生一次,当第 i 个事件发生时会分别让 X, Y, Z 增加Ai , Bi ,Ci 。
当游戏结束时 (所有事件的发生与否已经确定),如果 X, Y, Z 的其中一个大于另外两个之和,我们认为其获胜。例如,当 X > Y + Z 时,我们认为魏国获胜。小蓝想知道游戏结束时如果有其中一个国家获胜,最多发生了多少个事件?
如果不存在任何能让某国获胜的情况,请输出 −1 。
输入格式:
输入的第一行包含一个整数 n 。
第二行包含 n 个整数表示 Ai,相邻整数之间使用一个空格分隔。
第三行包含 n 个整数表示 Bi,相邻整数之间使用一个空格分隔。
第四行包含 n 个整数表示 Ci,相邻整数之间使用一个空格分隔。
3 1 2 2 2 3 2 1 0 7
输出:
2
思路:
这个题又是一道分类讨论题,如果放在一起想任意一国赢的情况基本想不到排序,更想不到贪心,这个题和“平均 ”那个题一样,都是 分类讨论!!!
我们先处理A国:若想让A胜利,那就看每个事件的净增加人数,我们要的事件越多越好。对另外两个国家也是这样
#include <bits/stdc++.h>
using namespace std; //贪心
int tmp[3][100005];
struct node{
int a,b,c;
}ar[100005];
bool cmp1(node x,node y){
return x.a-x.b-x.c>y.a-y.b-y.c;
}
bool cmp2(node x,node y){
return (x.b-x.a-x.c)>(y.b-y.a-y.c);
}
bool cmp3(node x,node y){
return x.c-x.a-x.b>y.c-y.b-y.a;
}
int main(){
int n,ans=0,cnt=0,lost=0;long long sign;
cin>>n;
for(int j=0;j<3;j++){
for(int i=1;i<=n;i++) //数据输入的方式十分奇葩
cin>>tmp[j][i];
}
for(int i=1;i<=n;i++){
ar[i].a=tmp[0][i];
ar[i].b=tmp[1][i];
ar[i].c=tmp[2][i];
}
//对A国获胜求最大事件
sort(ar+1,ar+n+1,cmp1);
sign=ar[1].a-ar[1].b-ar[1].c;
if(sign>0) {
cnt=1;
for(int i=2;sign>0&&i<=n;i++){
sign+=(ar[i].a-ar[i].b-ar[i].c);cnt++;
}
cnt--;
}else cnt=0,lost++;
ans=cnt;
//对B国获胜求最大事件
sort(ar+1,ar+n+1,cmp2);
sign=ar[1].b-ar[1].a-ar[1].c;
if(sign>0){
cnt=1;
for(int i=2;sign>0&&i<=n;i++){
sign+=(ar[i].b-ar[i].a-ar[i].c);cnt++;
}
cnt--;
}else cnt=0,lost++;
ans=max(ans,cnt);
//对C国获胜求最大事件
sort(ar+1,ar+n+1,cmp3);
sign=ar[1].c-ar[1].b-ar[1].a;
if(sign>0){
cnt=1;
for(int i=2;sign>0&&i<=n;i++){
sign+=(ar[i].c-ar[i].b-ar[i].a);cnt++;
}
cnt--;
}else cnt=0,lost++;
//特判
if(lost==3){
cout<<-1;return 0;
}
ans=max(ans,cnt);
cout<<ans;
return 0;
}
题目:子矩阵
给定一个 n × m (n 行 m 列)的矩阵。
设一个矩阵的价值为其所有数中的最大值和最小值的乘积。求给定矩阵的所有大小为 a × b (a 行 b 列)的子矩阵的价值的和。
答案可能很大,你只需要输出答案对 998244353 取模后的结果。
输入格式:
输入的第一行包含四个整数分别表示 n, m, a, b ,相邻整数之间使用一个空格分隔。
接下来 n 行每行包含 m 个整数,相邻整数之间使用一个空格分隔,表示矩阵中的每个数 Ai, j 。
2 3 1 2 1 2 3 4 5 6
输出格式:
58
思路:
完完全全的一道裸的二维单调队列的题,直接上模板就行
#include <bits/stdc++.h>
using namespace std; //二维单调队列
const int mod=998244353;
long long ans;
int n,m,a,b;
long long c[1000][1000],min1[1000][1000],min2[1000][1000],max1[1000][1000],max2[1000][1000];
void print(){
for(int i=1;i<=n-a+1;i++){//完全更新后的矩阵的行列数
for(int j=1;j<=m-b+1;j++){
ans=(ans+max2[i][j]*min2[i][j])%mod; //对结果取模
}
}
cout<<ans;
}
void two_deque(){ //二维单调队列
int H,T,h,t,Q[1000]={0},q[1000]={0};
for(int i=1;i<=n;i++){
H=T=h=t=q[1]=Q[1]=1;
if(b==1){ //对边长为1的特判
memcpy(min1,c,sizeof(min1));memcpy(max1,c,sizeof(max1));break;
}
for(int j=2;j<=m;j++){
while(c[i][q[t]]>c[i][j]&&h<=t) t--;q[++t]=j;
while(c[i][Q[T]]<c[i][j]&&H<=T) T--;Q[++T]=j;
while(q[h]+b<=j) h++;
while(Q[H]+b<=j) H++;
if(j>=b)min1[i][j-b+1]=c[i][q[h]],max1[i][j-b+1]=c[i][Q[H]];
}
}
for(int j=1;j<=m-b+1;j++){ //注意初步更新后矩阵的行列数
H=T=h=t=q[1]=Q[1]=1;
if(a==1){
memcpy(min2,min1,sizeof(min2));memcpy(max2,max1,sizeof(max2));break;
}
for(int i=2;i<=n;i++){
while(min1[q[t]][j]>min1[i][j]&&h<=t) t--;q[++t]=i;
while(max1[Q[T]][j]<max1[i][j]&&H<=T) T--;Q[++T]=i;
while(q[h]+a<=i) h++;
while(Q[H]+a<=i) H++;
if(i>=a)min2[i-a+1][j]=min1[q[h]][j],max2[i-a+1][j]=max1[Q[H]][j];
}
}
print();
}
int main(){
cin>>n>>m>>a>>b;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%lld",&c[i][j]);
}
}
two_deque();
return 0;
}