NOI Online 2020 #1

咕了一年的补题……


提高组

冒泡排序

令 \(x_i=\sum_{j=1}^{i-1}[x_j>x_i]\),则 \(k\) 次冒泡排序相当于将所有 \(x_i\) 变成 \(\max\{0,x_i-k\}\),树状数组维护即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
const int N=2e5+10;
int a[N],p[N],n;
struct bit
{
	int c[N];
	void init(){memset(c,0,sizeof(c));}
	int query(int x,int ans=0){for(;x;x-=x&-x)ans+=c[x];return ans;}
	void modify(int x,int d)
	{
		if(x==0)return;
		for(;x<=n;x+=x&-x)c[x]+=d;
	}
}t1,t2;
signed main()
{
//	freopen("P6186_1.in","r",stdin);
//	freopen("out.txt","w",stdout);
	n=read();int m=read();
	t1.init();
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
		p[i]=t1.query(n)-t1.query(a[i]);
		t1.modify(a[i],1);
	}
//	for(int i=1;i<=n;i++)printf("%d ",p[i]);
//	puts("");
	t1.init();t2.init();
	for(int i=1;i<=n;i++)t2.modify(p[i],p[i]),t1.modify(p[i],1);
	for(int i=1;i<=m;i++)
	{
		int pos=read();
		if(pos==1)
		{
//			puts("haha");
			int x=read();
			if(a[x]<a[x+1])
			{
				t2.modify(p[x],-p[x]);t2.modify(p[x+1],-p[x+1]);
				t1.modify(p[x],-1);t1.modify(p[x+1],-1);
				swap(a[x],a[x+1]);swap(p[x],p[x+1]);
				p[x+1]++;
				t2.modify(p[x],p[x]);t2.modify(p[x+1],p[x+1]);
				t1.modify(p[x],1);t1.modify(p[x+1],1);
			}
			else
			{
//				puts("t2.modify");
				t2.modify(p[x],-p[x]);t2.modify(p[x+1],-p[x+1]);
//				puts("t1.modify");
				t1.modify(p[x],-1);t1.modify(p[x+1],-1);
				swap(a[x],a[x+1]);swap(p[x],p[x+1]);
				p[x]--;
//				printf("p[x+1]:%d\n",p[x+1]);
//				puts("t2.modify");
				t2.modify(p[x],p[x]);t2.modify(p[x+1],p[x+1]);
//				puts("t1.modify");
				t1.modify(p[x],1);t1.modify(p[x+1],1);
			}
//			puts("HAHA");
		}
		else
		{
//			puts("hehe");
			int k=read();
			if(k>n){puts("0");continue;}
			int cnt=t1.query(n)-t1.query(k),sum=t2.query(n)-t2.query(k);
			printf("%lld\n",sum-k*cnt);
//			puts("HEHE");
		}
	}
	return 0;
}

序列

咕咕咕

最小环

咕咕咕


普及组

买铅笔

咋写都能过

跑步

反正NOIP不考五边形数

魔法

SF的题解

考虑 \(k=1\) 的情况,设 \(f(x,i,j)\) 表示 \(i\sim j\) 用了 \(k\) 次魔法的最小代价,则:

\[f(1,i,j)=\min_{(u,v,w)\in E}\{f(0,i,u)+f(0,v,j)-w\} \]

接下来考虑 \(k\ge 2\) 的情况,有:

\[f(x,i,j)=\min_{u=1}^n\{f(x-1,i,u)+f(1,u,j)\} \]

一个经典的矩乘式子,建立矩阵跑快速幂即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
const int N=110;
int n;
int e[N][N],f[N][N];
struct mat
{
	int a[N][N];
	mat(){memset(a,0x3f,sizeof(a));}
	void init(){for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)a[i][j]=e[i][j];}
	mat operator * (const mat &x) const
	{
		mat ans;
		for(int k=1;k<=n;k++)
			for(int i=1;i<=n;i++)
				for(int j=1;j<=n;j++)
					ans.a[i][j]=min(ans.a[i][j],a[i][k]+x.a[k][j]);
		return ans; 
	}
};
struct Edge
{
	int u,v,w;
	Edge(int uu,int vv,int ww){u=uu;v=vv;w=ww;}
	Edge(){}
}a[2510];
mat qpow(mat a,int n)
{
	mat ans;
	ans.init();
	while(n)
	{
		if(n&1)ans=ans*a;
		a=a*a;
		n>>=1;
	}
	return ans;
}
signed main()
{
//	freopen("P6190_3.in","r",stdin);
	memset(e,0x3f,sizeof(e));
	n=read();int m=read(),k=read();
	for(int i=1;i<=n;i++)e[i][i]=0;
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read(),w=read();
		e[u][v]=min(e[u][v],w);
		a[i]=Edge(u,v,w);
	}
	for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)e[i][j]=min(e[i][j],e[i][k]+e[k][j]);
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)f[i][j]=e[i][j];
	for(int k=1;k<=m;k++)
	{
		int u=a[k].u,v=a[k].v,w=a[k].w;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				f[i][j]=min(f[i][j],e[i][u]+e[v][j]-w);
	}
	mat x;
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)x.a[i][j]=f[i][j];
	mat ans=qpow(x,k);
	printf("%lld",k==0?e[1][n]:ans.a[1][n]);
	return 0;
}
上一篇:MySQL 5.7 特性:Online DDL


下一篇:mysql修改表结构出现唯一索引冲突