A 直接全用横着放
偶数列全放两个,奇数列最后放三个
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
using node=tuple<int,int,int>;
const long long inf=1e18;
int n,m,k;
void solve()
{
cin>>n>>m;
if(m%2==0) cout<<n*(m/2)<<"\n";
else {
cout<<n*((m-1)/2)<<"\n";
}
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
B.
我想的是对每个ai 和bi单独思考,因为可以随便排
考虑一对位置 i,j 交换
ai>aj and bi>bj 交换减少两对
ai>aj and bi<bj 无变化
ai<aj and bi<bj 增加两个
ai<aj and bi>bj 无变化
所以我是按ai逆序对数量+bi逆序对排的
越大的数在越后面逆序对越小
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
using node=tuple<int,int,int>;
const long long inf=1e18;
int n,m,k;
PII a[N];
int c[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].first;
for(int i=1;i<=n;i++) cin>>a[i].second;
sort(a+1,a+1+n,[&](const auto&p,const auto&q){
return p.first+p.second<q.first+q.second;
});
for(int i=1;i<=n;i++){
cout<<a[i].first<<" \n"[i==n];
}
for(int i=1;i<=n;i++){
cout<<a[i].second<<" \n"[i==n];
}
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
C:
这个题力扣好像似曾相似ahhh
就是贪心从大到小如果第i位无法避免是 0 1,你x的第i位无论取什么一定存在这个差值
所以记录当前位是a还是b
后面全部位都让另一个进来变大
比如 2^4>=2^3+2^2+2^1+2^0
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
using node=tuple<int,int,int>;
const long long inf=1e18;
int n,m,k;
PII a[N];
int c[N];
void solve()
{
// cin>>n;
// for(int i=1;i<=n;i++) cin>>a[i].first;
// for(int i=1;i<=n;i++) cin>>a[i].second;
// for(int i=1;i<=n;i++){
// }
int a,b,n;
cin>>a>>b>>n;
auto get=[&](int a,int b)->int{
int x=0;
int now=-1;
for(int i=60;i>=0;i--)
{
int l=(a>>i&1),r=(b>>i&1);
if(l==r) continue;
if(now!=-1)
{
if(now==a){
if(r==0&&x+(1ll<<i)<=n)
{
x+=(1ll<<i);
}
}
else{
if(l==0&&x+(1ll<<i)<=n)
{
x+=(1ll<<i);
}
}
}
if(now==-1)
{
if(l==0)
{
now=b;
}else{
now=a;
}
}
}
return abs((a^x)-(b^x));
};
int res=get(a,b);
swap(a,b);
cout<<min(get(a,b),res)<<"\n";
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
D:
可以想到得是答案是有单调性得,因为是取max,答案越大能完成可能性越大
然后check函数里面可以dp
dp状态就是:前1-i个数里面最小需要提出来的数得元素总和
那么f[i] 第i个位置可以提出去也可以不提出去
假设提出去第i个位置 f[i]=f[j-1]+a[i]
更一般得
假设当前提得是 j [ i]
s[i]-s[j]里面得总和小于等于x,那么j这个位置可以提出去
如果提出去代价就是f[j-1] + a[j]代表a[j]这个数一定要提出去
然后代码里注释的就是暴力,观察可以得到优化可以单调队列或者线段树或者优先队列都是可以得
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const long long inf=1e18;
int n,m,k;
int a[N],s[N],b[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];
auto check=[&](int x)
{
vector<int> f(n+10,2e18);
f[0]=0;
for(int i=1,j=0;i<=n;i++){
j+=a[i];
if(j<=x){
f[i]=0;
}else break;
}
int idx=0;
priority_queue<PII,vector<PII>,greater<PII>> q;
for(int i=1;i<=n;i++)
{
f[i]=min(f[i],f[i-1]+a[i]);
while(q.size()&&s[i]-s[q.top().second]>x){
q.pop();
}
if(q.size())
f[i]=min(f[i],q.top().first);
q.emplace(f[i-1]+a[i],i);
// for(int j=1;j<=i;j++)
// {
// if(s[i]-s[j]<=x)
// f[i]=min(f[i],f[j-1]+a[j]);
// }
}
return f[n]<=x;
};
int l=*max_element(a+1,a+1+n),r=s[n];
while(l<r){
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<l<<"\n";
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const long long inf=1e18;
int n,m,k;
int a[N],s[N],b[N];
struct node{
int l,r;
int v;
}tr[N*4];
void pushup(int u) // 由子节点的信息,来计算父节点的信息
{
tr[u].v = min(tr[u << 1].v, tr[u << 1 | 1].v);
}
void build(int u, int l, int r)
{
tr[u] = {l, r,inf};
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
int query(int u, int l, int r)
{
if (tr[u].l >= l && tr[u].r <= r) return tr[u].v; // 树中节点,已经被完全包含在[l, r]中了
int mid = tr[u].l + tr[u].r >> 1;
int v = 2e18;
if (l <= mid) v = query(u << 1, l, r);
if (r > mid) v = min(v, query(u << 1 | 1, l, r));
return v;
}
void modify(int u, int x, int v)
{
if (tr[u].l == x && tr[u].r == x) tr[u].v = v;
else
{
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];
auto check=[&](int x)
{
build(1,1,n);
vector<int> f(n+10,2e18);
f[0]=0;
for(int i=1,j=0;i<=n;i++){
j+=a[i];
if(j<=x){
f[i]=0;
}else break;
}
int idx=0;
for(int i=1;i<=n;i++)
{
f[i]=min(f[i],f[i-1]+a[i]);
while(idx<=i&&s[i]-s[idx]>x){
idx++;
}
f[i]=min(f[i],query(1,idx,i));
modify(1,i,f[i-1]+a[i]);
// for(int j=1;j<=i;j++)
// {
// if(s[i]-s[j]<=x)
// f[i]=min(f[i],f[j-1]+a[j]);
// }
}
return f[n]<=x;
};
//cout<<check(7)<<"\n";
int l=*max_element(a+1,a+1+n),r=s[n];
while(l<r){
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<l<<"\n";
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}