1.最大的和
思路:利用前缀和把二维数组的一行看成一个整体,然后数组就降到了一维,利用一位数组求连续区间最大值,求就可以了
代码
#include<bits/stdc++.h>
using namespace std;
int pre[110][110];
int a[110][110];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
pre[i][j]=pre[i][j-1]+a[i][j];
}
}
int ans=-999999999;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
int l=0;
for(int k=1;k<=n;k++)
{
if(l<0)
{
l=pre[k][j]-pre[k][i-1];
}
else
{
l+=pre[k][j]-pre[k][i-1];
}
ans=max(ans,l);
}
}
}
cout<<ans<<endl;
}
2.动态中位数
思路:利用大根堆和下根堆模拟中位数左右的边的数的情况,如果大根堆为空或数字大于大根堆顶,插入大根堆,否则插入小根堆,如果大根堆的数字个数大于小根堆+1,要匀一个个小根堆,如果小根堆的数字个数大于大根堆,要匀一个个大根堆,(插入奇数个时,大根堆比小根堆多一个,偶数个时,两边数量一样)
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
priority_queue<int> left;
priority_queue<int,vector<int>,greater<int>> right;
int id,num;
scanf("%d%d",&id,&num);
printf("%d %d\n",id,(num+1)>>1);
int cnt=0;
for(int i=1; i<=num; i++)
{
int x;
scanf("%d",&x);
if(left.empty()||x<=left.top())
{
left.push(x);
}
else
{
right.push(x);
}
if(left.size()>=right.size()+2)
{
right.push(left.top()),left.pop();
}
if(right.size()>left.size())
{
left.push(right.top()),right.pop();
}
if(i%2)
{
printf("%d ",left.top());
cnt++;
if(cnt%10==0)
{
printf("\n");
}
}
}
if(cnt%10)
printf("\n");
}
}
3.超快速排序
思路:求逆序对模板题,利用树状数组求就行了,离散化的时候要注意离散的数字里面有0
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
struct k
{
long long int data;
int wz;
}a[600000];
long long int b[600000]={0};
long long int tree[600005]={0};
int low(int x)
{
return x&-x;
}
bool cmp(struct k x1,struct k x2)
{
return x1.data<x2.data;
}
void add(int x)
{
while(x<=n)
{
tree[x]++;
x+=low(x);
}
}
long long int getsum(int x)
{
long long int ans=0;
while(x!=0)
{
ans+=tree[x];
x-=low(x);
}
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF){
if(n==0)break;
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i].data);
a[i].wz=i;
}
sort(a+1,a+n+1,cmp);
int cnt=0;
for(int i=1;i<=n;i++)
{
if(a[i].data!=a[i-1].data)
{
cnt++;
}
b[a[i].wz]=cnt;
}
long long int ans=0;
for(int i=1;i<=n;i++)
{
add(b[i]);
ans+=i-getsum(b[i]);//减去前面比他小的
}
printf("%lld",ans);
}
}
4.奇数码问题
思路:看了一下n的范围,搜索是不可能的,看了一眼标签和逆序对有关,如果把二维地图,一维展开成一行,左右移动不影响逆序对的数量,上下移动,相当于一个数字前进或后退n-1个位置,根据奇偶性原理,如果移动的影响是偶数的话奇偶性不变,那么问题转变成初始态和结束态的逆序对数量的差的奇偶性问题了,如果为偶输出TAK(可以转变),否则输出NIE(不可以转变)
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll tree[250010];
ll a[250010],b[250010];
ll n;
ll low(ll x)
{
return x&-x;
}
void add(ll x)
{
while(x<=n*n-1)
{
tree[x]++;
x+=low(x);
}
}
ll getSum(ll x)
{
ll ans=0;
while(x)
{
ans+=tree[x];
x-=low(x);
}
return ans;
}
ll nx(ll sum[250010])
{
memset(tree,0,sizeof(tree));
ll ans=0;
for(int i=1; i<=n*n-1; i++)
{
add(sum[i]);
ans+=i-getSum(sum[i]);
}
return ans;
}
int main()
{
while(cin>>n)
{
ll cnt=1;
for(int i=1; i<=n*n; i++)
{
ll x;
cin>>x;
if(x==0)
{
continue;
}
a[cnt++]=x;
}
cnt=1;
for(int i=1; i<=n*n; i++)
{
ll x;
cin>>x;
if(x==0)
{
continue;
}
b[cnt++]=x;
}
if(abs(nx(a)-nx(b))%2==0)
{
cout<<"TAK"<<endl;
}
else
{
cout<<"NIE"<<endl;
}
}
}