zoukankan      html  css  js  c++  java
  • NOI Online 2020 #1

    咕了一年的补题……


    提高组

    冒泡排序

    (x_i=sum_{j=1}^{i-1}[a_j>a_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
    ",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
    ",sum-k*cnt);
    //			puts("HEHE");
    		}
    	}
    	return 0;
    }
    

    序列

    stO xht Orz

    对于操作 (2) 连边,形成若干连通块,在和不变的情况下这些连通块内的点的点权能变成任何数。

    将上面这些连通块缩点之后再对于操作 (1) 连边,如果最后形成的图是二分图,那么在左边右边的差不变的情况下能成为任何数,反之在左边右边差的奇偶性不变的情况下能变成任何数。

    #include<bits/stdc++.h>
    using namespace std;
    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=1e5+10,M=2e5+10;
    struct bjc
    {
    	int f[N];
    	void init(int n){for(int i=1;i<=n;i++)f[i]=i;}
    	int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}
    	void merge(int x,int y){f[getf(y)]=getf(x);}
    }t;
    int head[N],ver[M],nxt[M],tot=0;
    void add(int x,int y)
    {
    	ver[++tot]=y;
    	nxt[tot]=head[x];
    	head[x]=tot; 
    }
    struct Edge
    {
    	int u,v;
    	Edge(int uu,int vv){u=uu;v=vv;}
    	Edge(){}
    }e[M];
    int col[N],s[N],d[N];
    bool dfs(int x,int c)
    {
    	s[col[x]=c]+=d[x];bool f=1;
    	for(int i=head[x];i;i=nxt[i])
    	{
    		int y=ver[i];
    		if(~col[y]){if(col[y]==col[x])f=0;continue;}
    		if(!dfs(y,c^1))f=0;
    	}
    	return f;
    }
    int a[N],b[N];
    void sol()
    {
    	memset(d,0,sizeof(d)); 
    	memset(head,0,sizeof(head));tot=0;
    	int n=read(),m=read(),cnt=0;
    	for(int i=1;i<=n;i++)a[i]=read();
    	for(int i=1;i<=n;i++)b[i]=read();
    	t.init(n);
    	for(int i=1;i<=m;i++)
    	{
    		int tt=read(),u=read(),v=read();
    		if(tt==2)t.merge(u,v);
    		else e[++cnt]=Edge(u,v);
    	}
    	for(int i=1;i<=n;i++)d[t.getf(i)]+=b[i]-a[i];
    	for(int i=1;i<=cnt;i++)
    	{
    		add(t.getf(e[i].u),t.getf(e[i].v));
    		add(t.getf(e[i].v),t.getf(e[i].u));
    	}
    	memset(col,-1,sizeof(col));
    	for(int i=1;i<=n;i++)
    	{
    		if(~col[i])continue;
    		s[0]=s[1]=0;
    		bool f=dfs(i,0);
    		if(!f&&abs(s[0]%2)!=abs(s[1]%2)){puts("NO");return;}
    		if(f&&s[0]!=s[1]){puts("NO");return;}
    	}
    	puts("YES");
    }
    int main()
    {
    	int T=read();
    	while(T--)sol();
    	return 0;
    }
    

    最小环

    显然原图必将分出 (gcd(n,k)) 个大小为 (n/gcd(n,k)) 的独立的环。考虑分别处理每一个环,那么一定是尽量将大的与大的乘,可以证明这样是最优的。

    对于每个询问都做一遍是 (mathcal O(nm)) 的,不太行,发现 (gcd(n,k)) 最多有 (sigma_0(n)) 个,预处理即可。

    时间复杂度 (mathcal O(nsigma_0(n)+m))

    #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],n,f[N];
    int sol(int g)//g:环大小 
    {
    	deque<int> que;
    	int ans=0;
    	for(int j=1;j<=n/g;j++)
    	{
    		while(!que.empty())que.pop_back();
    		que.push_back(a[j*g]);
    		for(int i=j*g-1;i>=(j-1)*g+2;i--)
    		{
    			if(que.front()>que.back())ans+=a[i]*que.front(),que.push_front(a[i]);
    			else ans+=a[i]*que.back(),que.push_back(a[i]);
    		}
    		int x=a[(j-1)*g+1];
    		ans+=x*que.back()+x*que.front();
    	}
    	return ans;
    }
    int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
    signed main()
    {
    	n=read();int m=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	sort(a+1,a+n+1);
    	int ans=0;
    	for(int i=1;i<=n;i++)ans+=a[i]*a[i];
    	for(int i=1;i*i<=n;i++)
    	{
    		if(n%i)continue;
    		f[i]=sol(i);
    		if(i*i!=n)f[n/i]=sol(n/i);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		int x=read();
    		if(!x)printf("%lld
    ",ans);
    		else printf("%lld
    ",f[n/gcd(n,x)]);
    	}
    	return 0;
    }
    

    普及组

    买铅笔

    枚举即可。

    跑步

    反正NOIP不考五边形数

    魔法

    SF的题解

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

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

    接下来考虑 (kge 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;
    }
    
  • 相关阅读:
    1.淡入淡出效果js原生代码2.缓冲运动
    php 图片加水印插件
    php redis使用 常用方法 | Windows环境下安装Redis | Windows下php安装redis扩展(详解版)
    Windows下安装使用workman简单实例
    极简生成excel方法;excel表导入数据库
    php 生成表单 | url串禁止转义并解决中文字符乱码
    图片上传预览并保存图片 | 多图上传预览并保存图片 | 树状结构(jquery.treeview.js)
    php Rsa签名算法
    php 正则表达式 1.字符串中提取带小数点的数字 2.判断字符串中是否包含关键字 3.统计二维数组中某个字段值出现的次数
    虚拟主机部署tp项目,在.htaccess文件中隐藏index.php
  • 原文地址:https://www.cnblogs.com/juruo-zzt/p/14780910.html
Copyright © 2011-2022 走看看