NOI online #1 提高组
序列#
题意:
给定数组,有两种操作:
选择两个位置,使得都加一或减一
选择两个位置使得加一,减一,或者反过来。
给出的操作可以做任意次,问数组能否变成数组?
题解:
考虑操作二,因为可以在里面任意分配权值,可以缩点。
然后把操作一对应的点连边,对于任意连通块:
如果是二分图,那么左部点和右部点的权值和之差不变,必须为
如果不是二分图,那么连通块内点数和必须是偶数。
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
const int N=1e5+10;
int n,m;
int a[N],b[N],s[N],c[5];
int f[N],col[N];
vector<int> eg[N];
struct node
{
int x,y;
}q[N];
int num;
inline int find(int k){return f[k]==k?k:f[k]=find(f[k]);}
inline void init()
{
num=0;
for(int i=1;i<=n;++i)
{
eg[i].clear();
f[i]=i;
s[i]=col[i]=0;
}
}
inline bool dfs(int now,int cc)
{
col[now]=cc;
c[cc]+=s[now];
bool flag=1;
for(int t:eg[now])
{
if(col[t]==col[now]) flag=0;
if(!col[t]&&!dfs(t,3-cc)) flag=0;
}
return flag;
}
inline void main()
{
int skx;cin>>skx;
while(skx--)
{
cin>>n>>m;
init();
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i) cin>>b[i];
for(int i=1;i<=m;++i)
{
int opt,x,y;
cin>>opt>>x>>y;
if(opt==1) q[++num].x=x,q[num].y=y;
else f[find(x)]=find(y);
}
for(int i=1;i<=n;++i)
{
s[find(i)]+=a[i]-b[i];
}
for(int i=1;i<=num;++i)
{
int x=find(q[i].x),y=find(q[i].y);
eg[x].emplace_back(y);
eg[y].emplace_back(x);
}
bool flag=1;
for(int i=1;i<=n;++i) if(!col[i]&&find(i)==i)
{
c[1]=c[2]=0;
bool ok=dfs(i,1);
if(ok&&c[1]!=c[2]) {flag=0;break;}
if(!ok&&(c[1]^c[2])&1) {flag=0;break;}
}
if(flag) cout<<"YES\n";
else cout<<"NO\n";
}
}
}
signed main()
{
red::main();
return 0;
}
/*
*/
冒泡排序#
题意:
给定一个排列
有两个操作:
把交换位置。
问这个排列做次冒泡排序后的逆序对数。
题解:
假设一个序列的逆序对数是:
那么做一个冒泡排序后的逆序对数就是:
当然,和取
有了这个性质之后怎么做呢,其实不用真的去移位,因为第一位的逆序对数肯定,等于是把第一位剪掉就行了。
而次之后就是
所有项和取,然后求和,显然可以树状数组。
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
const int N=3e5+10;
int n,m;
int a[N],p[N];
struct BIT
{
int tr[N];
inline void update(int x,int k)
{
for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=k;
}
inline int query(int x)
{
int sum=0;
for(int i=x;i>=1;i-=lowbit(i)) sum+=tr[i];
return sum;
}
}T[2];
inline void main()
{
cin>>n>>m;
for(int i=1;i<=n;++i)
{
cin>>p[i];
T[0].update(p[i],1);
a[i]=i-T[0].query(p[i]);
}
for(int i=1;i<=n;++i) T[0].tr[i]=0;
for(int i=1;i<=n;++i) T[0].update(n-a[i],1),T[1].update(n-a[i],a[i]);
for(int i=1;i<=m;++i)
{
int opt,x;
cin>>opt>>x;
if(opt==1)
{
T[0].update(n-a[x],-1);
T[1].update(n-a[x],-a[x]);
T[0].update(n-a[x+1],-1);
T[1].update(n-a[x+1],-a[x+1]);
if(p[x]>p[x+1]) --a[x+1];
swap(p[x],p[x+1]);
swap(a[x],a[x+1]);
if(p[x]>p[x+1]) ++a[x+1];
T[0].update(n-a[x],1);
T[1].update(n-a[x],a[x]);
T[0].update(n-a[x+1],1);
T[1].update(n-a[x+1],a[x+1]);
}
else
{
int sum=T[0].query(n-x);
int val=T[1].query(n-x);
cout<<val-x*sum<<'\n';
}
}
}
}
signed main()
{
red::main();
return 0;
}
/*
*/
最小环#
题意:
给个数字,每次给一个数字,要求把个数字排成一个环,让环上所有距离为的两个数字的乘积的和最大。
题解:
每个数字会把整个环分成几个不相交的小环,为了让积之和最大,我们尽量让大的乘大的,小的乘小的,所以最大的数字都应该分给同一个环,然后类推。
在一个环内怎么排列呢?我们先把最大的数字放进去,然后去考虑第二大的,让当前数字尽量挨着大的数字放:
大概是以上模式插入,其中首尾是相接的。
数字是怎么把长度为的环分割的呢?其实就是分成个环,每个长度是。
所以不同的情况其实只有种,其中是的约数个数。
所以时间复杂度
还可以更优,注意对于只有一个环的情况,其他情况和它的区别只在两个环的交界处,对于个环,只要的时间算一下交界。
总复杂度,是调和级数。约等于
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
const int N=3e5+10;
int n,m;
int a[N];
int st[2][N],top[2];
int ret[N];
inline void main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
int sum=0;
for(int i=1;i<=n;++i)
{
cin>>a[i];
sum+=a[i]*a[i];
}
sort(a+1,a+n+1);
for(int i=1;i<=m;++i)
{
int k;cin>>k;
if(!k)
{
cout<<sum<<'\n';
continue;
}
int t=__gcd(n,k);
int d=n/t;
if(ret[d])
{
cout<<ret[d]<<'\n';
continue;
}
for(int j=0;j<t;++j)
{
int l=j*d+1,r=(j+1)*d;
top[0]=top[1]=0;
st[0][++top[0]]=a[r];
st[1][++top[1]]=a[r--];
while(r>l)
{
int b=0;
if(st[0][top[0]]<st[1][top[1]]) b=1;
ret[d]+=a[r]*st[b][top[b]];
st[b][++top[b]]=a[r--];
}
ret[d]+=a[l]*(st[0][top[0]]+st[1][top[1]]);
}
cout<<ret[d]<<'\n';
}
}
}
signed main()
{
red::main();
return 0;
}
/*
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】