// LUOGU_RID: 149552918
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=2*N,mod=1e9+7;
#define int long long
#define uLL unsigned long long
const long long inf=2e18;
typedef pair<int,int> PII;
typedef long long LL;
using node=tuple<int,int,int>;
int n,m,k;
int a[N];
void solve()
{
cin>>n;
string s;cin>>s;
string t=s;reverse(t.begin(),t.end());
if(s<=t){
cout<<s<<"\n";
}else
{
cout<<t+s<<"\n";
}
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
A:因为n是偶数显然操作只有两种
1.翻转使得答案不变
2.添加后翻转之后再翻转
实际是要么s开始头要么t开始,直接比较s和t字典序即可
B.如果两个区间的mex相同,那么合并了也是相同的,所以假设k>=3满足,那么k=2也满足
问题变成了求前缀和后缀那个点的mex相同,直接预处理即可
// LUOGU_RID: 149556222
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=2*N,mod=1e9+7;
#define int long long
#define uLL unsigned long long
const long long inf=2e18;
typedef pair<int,int> PII;
typedef long long LL;
using node=tuple<int,int,int>;
int n,m,k;
int a[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
vector<int> l(n+10),r(n+10);
set<int> st;
int now=0;
for(int i=1;i<=n;i++){
st.insert(a[i]);
while(st.count(now)) now++;
l[i]=now;
}
now=0;st.clear();
for(int i=n;i>=1;i--){
st.insert(a[i]);
while(st.count(now)) now++;
r[i]=now;
}
for(int i=1;i<n;i++){
if(l[i]==r[i+1]){
cout<<2<<"\n";
cout<<1<<" "<<i<<"\n";
cout<<i+1<<" "<<n<<"\n";
return ;
}
}
cout<<"-1\n";
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
C:
分解式子假设点选定了,那么a的总和固定的,且b一定是从小到大排序的最优解
b一定是从小到大排序可以得到我们加入一个新点的时候,一定是大的放在小的后面
那么我们dp要先进行b数组排序
方程就是第i个点为最后一个点的时候,序列已经有j个数的最小值
方程就是f[i][j]=min(f[i][j],f[k][j-1]+a[i]-b[i]-b[k]) (k<i)
复杂度是n^3
合并同类
f[k][j-1]-b[k] 和a[i]-b[i]可以分开,第一项直接预处理即可
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=2*N,mod=1e9+7;
#define int long long
#define uLL unsigned long long
const long long inf=2e18;
typedef pair<int,int> PII;
typedef long long LL;
using node=tuple<int,int,int>;
int n,m,k;
PII a[N];
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i].first>>a[i].second;
sort(a+1,a+1+n,[&](const auto&p,const auto&q){
return p.second<q.second;
});
vector<vector<int>> f(n+10,vector<int>(n+10,inf));
f[0][0]=0;
vector<int> pre(n+10,inf);
for(int i=1;i<=n;i++)
{
f[i][1]=a[i].first;
for(int j=2;j<=n;j++)
{
f[i][j]=min(f[i][j],a[i].first+a[i].second+pre[j-1]);
}
for(int j=1;j<=n;j++)
pre[j]=min(pre[j],f[i][j]-a[i].second);
}
int res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(f[i][j]<=m) res=max(res,j);
}
}
cout<<res<<"\n";
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
贪心:
因为b一定是从小到大排序的,实际答案就是最大的b[i]减掉最小的b[k]
所以我们枚举左右端点,对于[l,r]的区间我们用个堆维护a[i]的总和即可
如果堆把左端点弹出去了,到底合不合法的问题,首先如果把左端点弹出去了,但我们依然用的是当前b[r]-b[l]他是大于把[l+1,r] 到r的,所以是合法的,
// LUOGU_RID: 149548787
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=2*N,mod=1e9+7;
#define int long long
#define uLL unsigned long long
const long long inf=2e18;
typedef pair<int,int> PII;
typedef long long LL;
using node=tuple<int,int,int>;
int n,m,k;
PII a[N];
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i].first>>a[i].second;
sort(a+1,a+1+n,[&](const auto&p,const auto&q){
return p.second<q.second;
});
int res=0;
//贪心只关心最后一个点和第一个点的距离
//中间
for(int i=1;i<=n;i++)
{
int now=0;
priority_queue<int> q;
for(int j=i;j<=n;j++){
now+=a[j].first;
q.emplace(a[j].first);
while(q.size()&&a[j].second-a[i].second+now>m){
now-=q.top();
q.pop();
}
res=max(res,(int)q.size());
}
}
cout<<res<<"\n";
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
D:很裸的一道容斥原理 x<=y<=c
总数-(x+y=a[i])的个数-(y-x=a[i])的个数+(x+y=a[j] and y-x=a[i])的个数
对于(x+y=a[i])的个数就是a[i]/2+1,就比如2 有(0,2) (1,1) 3有(0,3) (1,2)
对于 y-x=a[i]的个数就是 c-a[i]+1的个数
对于重复的满足
x+y=a[i]
y-x=a[j]
x+a[j]+x=a[i]
x=(a[j]-a[i])/2
满足 a[j]>=a[i] 且两个数能mod2 说明要么都是偶数要么都是奇数
统计即可
// LUOGU_RID: 149551811
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=2*N,mod=1e9+7;
#define int long long
#define uLL unsigned long long
const long long inf=2e18;
typedef pair<int,int> PII;
typedef long long LL;
using node=tuple<int,int,int>;
int n,m,k;
int a[N];
void solve()
{
int c;
cin>>n>>c;
int ou=0;
for(int i=1;i<=n;i++) cin>>a[i];
int res=(c+1)*c/2+c+1;
for(int i=1;i<=n;i++){
//删除x+y=a[i] and x<=y<=c and a[i]<=c
//删 y-x=a[i] and x<=y<=c and a[i]<=c
//x+y=ai
//y-x=aj
//x+aj+x=ai
//2x=ai-aj
//x=(ai-aj)/2
//重复说明存在(x,y)队
//说明两个数/2是偶数
res-=a[i]/2+1;
res-=(c-a[i])+1;
ou+=(a[i]%2==0);
}
res+=ou*(ou+1)/2;
res+=(n-ou)*(n-ou+1)/2;
cout<<res<<"\n";
//(0,1)
//(2,3) (1,2) (0,1)
//unique (0,1)
//(0,2) (1,1)
//(1,3) (0,2)
//unique (0,2)
//(0,3) (1,2)
//(0,3)
//unique(0,3)
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
E:
考虑单独一对 x ,y
100101
101010
首先最长公共前缀的数肯定是可以拥有的,我们记在数组f[i][j]
表示当前数的第j位的二进制肯定可以填1
去掉公共前面的10变成
0101
1010
分开了表示我们有两个选择,继续选1,或者选011
因为分开了说明当前点肯定比对面大,左端点最大肯定是011
记在g[i][j]
继续选1
那么第二位是不能变成1的,因为前面的1选了,如果当前还选1就超过y了
第三位同理我们要么继续当前位选1,或者选1001
如果如果当前区间的第j位的g有超过1个那么后面都能变成1
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=2*N,mod=1e9+7;
#define int long long
#define uLL unsigned long long
const long long inf=2e18;
typedef pair<int,int> PII;
typedef long long LL;
using node=tuple<int,int,int>;
int n,m,k;
int a[N];
int x[N],y[N];
void solve()
{
//10001001
//10100111
//对于每个li ri
//前缀相同固定要取得
//对于不同
//如果当前1得个数大于2
cin>>n;
vector<vector<int>> f(n+10,vector<int>(35));
vector<vector<int>> g(n+10,vector<int>(35));
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i];
bool flag=true;
for(int j=30;j>=0;j--)
{
f[i][j]=f[i-1][j];
g[i][j]=g[i-1][j];
}
for(int j=30;j>=0;j--)
{
if(((x[i]>>j&1) == (y[i]>>j&1))&&flag){
f[i][j]+=(x[i]>>j&1);
//当前位一定能用
}else if(flag)
{
//当前数开始不同
//y[i]>>j&1=1
flag=false;
g[i][j]++;
}else{
g[i][j]+=(y[i]>>j&1);
}
}
}
//3-10
//2 2
//0011
//1010
//0010
//0010
//3 4
//011
//100
cin>>m;
while(m--){
int l,r;cin>>l>>r;
int res=0;
for(int i=30;i>=0;i--)
{
int pref=f[r][i]-f[l-1][i];
int preg=g[r][i]-g[l-1][i];
if(preg && (preg+pref>=2))
{
res|=((1ll<<i+1)-1);
break;
}else if(pref>=1 || preg>=1){
res|=1ll<<i;
}
}
cout<<res<<" ";
}
cout<<"\n";
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}