河南萌新联赛3题解
1.
考虑一个区间的逆序对数,比如1 4 2 3顺着有两对,旋转后就有所有数对减去原来是逆序对的对数就是新有多少逆序对数。所以只要写个离线算法。计算每个区间有多少逆序对,旋转后只要拿区间数对数减去原逆序对数就是新的逆序对数量。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,char> PII;
#define fel(i,x,y) for(int i=x;i<=y;i++)
#define fhl(i,x,y) for(int i=x;i>=y;i--)
#define pb push_back
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define inf 0x3fffffff
#define endl "\n"
#define ll long long
const int N=6100;
int n,q;
int a[N];
int f[N][N];
int main(){
IOS
cin>>n;
fel(i,1,n) cin>>a[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) f[j][i]=f[j][i-1];
int t=0;
for(int j=i-1;j>=1;j--){
if(a[i]<a[j])t++;
f[j][i]+=t;
}
}
cin>>q;
while(q--){
int x,y;
cin>>x>>y;
ll t=(y-x+1)*(y-x)/2;
cout<<f[1][n]-f[x][y]+t-f[x][y]<<endl;
}
return 0;
}
2.
每个数的漂亮值很好求就是对每个数质因数分解,比如8就是2^3所以他的漂亮值就是3,这样每个数新乘上一个数肯定就是加他的漂亮值。这样就可以用线段树存每个点的贡献值了,乘上一个数就可以是区间加上这个数的贡献值。
那如何求每个数的贡献值呢?这可以在素数筛的过程中求解,如果prime[j]是质数,那他的漂亮值肯定是一。那prime[j]*i的漂亮值就是i的漂亮值加上一个1.
#include<bits/stdc++.h>
using namespace std;
#define fel(i,x,y) for(int i=x;i<=y;i++)
#define feh(i,x,y) for(int i=x;i>=y;i--)
#define ll long long
#define pb push_back
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl "\n"
#define int long long
//考虑用线段树存每个数的漂亮值贡献//
//然后如何求一个数的贡献了,分解质因数就好了,然后每个数的的漂亮值是是约数的指数和
//比如8=2^3就是3,10=2*5就是2
//这样操作之后就只需要套线段树模板就好。
//因为每次一个区间成乘上一个数就只要考虑把他的贡献加上去就好了
const int N=4e6+100;
int n,op,l,r,w,q;
int b[N],f[N];
int prime[N],cnt;
bool isprime[N];
int tag[N<<1],tree[N<<1];
void judge()
{
for(int i=2; i<=N; i++) {
if(!isprime[i]) {
f[i]=1;//质数的贡献肯定是1
prime[++cnt]=i;
}
for(int j=1; j<=cnt&&prime[j]*i<=N; j++) {
isprime[prime[j]*i]=1;
f[prime[j]*i]=f[i]+1;//相比于i多了一个质数
if(i%prime[j]==0) break;
}
}
}
int ls(int x)
{
return x<<1;
}
int rs(int x)
{
return x<<1|1;
}
void ff(int l,int r,int p,int k) //l-r区间加上一个k
{
tree[p]+=(r-l+1)*k;
tag[p]+=k;
}
void push_up(int p)
{
tree[p]=tree[ls(p)]+tree[rs(p)];
}
void push_down(int l,int r,int p)
{
ll mid=l+r>>1;
ff(l,mid,ls(p),tag[p]);
ff(mid+1,r,rs(p),tag[p]);
tag[p]=0;
}
inline void build(int l,int r,int p)
{
tag[p]=0;
if(l==r) {
tree[p]=b[l];
return;
}
ll mid=r+l>>1;
build(l,mid,ls(p));
build(mid+1,r,rs(p));
push_up(p);
}
inline void update(int nl,int nr,int l,int r,int p,int k) //在nl-nr的区间上加上k
{
if(nl<=l&&r<=nr) {
tree[p]+=(r-l+1)*k;
tag[p]+=k;
return;
}
push_down(l,r,p);
int mid=(l+r)>>1;
if(nl<=mid) update(nl,nr,l,mid,ls(p),k);
if(mid<nr) update(nl,nr,mid+1,r,rs(p),k);
push_up(p);
}
inline ll query(int nl,int nr,int l,int r,int p)
{
ll ans=0;
if(nl<=l&&r<=nr) {
return tree[p];
}
push_down(l,r,p);//注意先push_down再query
int mid=l+r>>1;
if(nl<=mid)ans+=query(nl,nr,l,mid,ls(p));
if(mid<nr)ans+=query(nl,nr,mid+1,r,rs(p));
return ans;
}
signed main()
{
IOS
judge();
cin>>n;
fel(i,1,n) {
cin>>b[i];
b[i]=f[b[i]];
}
// for(int i=1;i<=n;i++){
// cout<<b[i]<<" ";
// }
build(1,n,1);
cin>>q;
while(q--) {
cin>>op;
if(op==1) {
cin>>l>>r;
cout<<query(l,r,1,n,1)<<endl;
}
if(op==2) {
cin>>l>>r>>w;
update(l,r,1,n,1,f[w]);
}
}
return 0;
}
3.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
//感觉路的价值是动态变化的。如果下段路需要做和酸,则他的价值会上升x
int n,m,x;
ll head[100010],cnt,dis[100010];
bool vis[100010];//看是否已经确定了最大值
struct Edge{
ll to,dis,next;
}edge[500010];
struct node{
ll id,dis;
bool operator<(const node &x)const{
return x.dis<dis;
}
};
void add_edge(int from,int to,int dis){//链式前向星存图
edge[++cnt].to=to,
edge[cnt].dis=dis;
edge[cnt].next=head[from];
head[from]=cnt;
}
void dijkstra(){
int cnt=0;//cnt=0表示需要做核酸,cnt=1表示不需要做核酸
priority_queue<node>q;
for(int i=1;i<=n;i++) dis[i]=INT_MAX;
q.push({1,0});
dis[1]=0;
while(!q.empty()){
node a=q.top();
q.pop();
int now=a.id;
if(vis[now]) continue;
vis[now]=1;
int flag=0;
for(int i=head[now];i;i=edge[i].next){
int j=edge[i].to;
if(cnt==0){
if(dis[j]>dis[now]+edge[i].dis+x){
dis[j]=dis[now]+edge[i].dis+x;
if(vis[j]==0){
flag=1;
q.push({j,dis[j]});
}
}
}
else{
if(dis[j]>dis[now]+edge[i].dis){
dis[j]=dis[now]+edge[i].dis;
if(vis[j]==0){
flag=1;
q.push({j,dis[j]});
}
}
}
}
if(flag){
cnt^=1;
}
}
}
int main(){
cin>>n>>m>>x;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
add_edge(u,v,w);
add_edge(v,u,w);
}
dijkstra();
cout<<dis[n];
return 0;
}
4.
这个考虑同余的性质,就是两个数的差去取模为0的数肯定是这两个数的同余数。所以只要对a-b,a-c,b-c这三个数求解就共因数就好了。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,char> PII;
#define fel(i,x,y) for(int i=x;i<=y;i++)
#define fhl(i,x,y) for(int i=x;i>=y;i--)
#define pb push_back
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define inf 0x3fffffff
#define endl "\n"
#define ll long long
map<int,int>mp;
int a,b,c;
int main(){
IOS
int t;
cin>>t;
while(t--){
mp.clear();
cin>>a>>b>>c;
if(a==b&&b==c){
cout<<-1<<endl;
continue;
}
int t1=abs(a-b);
int t2=abs(a-c);
int t3=abs(b-c);
for(int i=1;i<=t1/i;i++){
if(t1%i==0){
mp[i]++;
if(i!=t1/i)mp[t1/i]++;
}
}
for(int i=1;i<=t2/i;i++){
if(t2%i==0){
mp[i]++;
if(i!=t2/i)mp[t2/i]++;
}
}
for(int i=1;i<=t3/i;i++){
if(t3%i==0){
mp[i]++;
if(i!=t3/i)mp[t3/i]++;
}
}
for(auto [x,y]:mp){
int q=a%x;
int w=b%x;
int e=c%x;
if(q==w&&w==e){
cout<<x<<" ";
}
}
cout<<endl;
}
return 0;
}

浙公网安备 33010602011771号