【学习笔记】ARC149

Two LIS Sum

结论是,其中一个序列的 L I S LIS LIS一定是 n n n这结论为啥我还想了半天啊

Avoid Prime Sum

简单构造题。分 n n n的奇偶性讨论,上半部分全填奇数,下半部分全填偶数,中间对于奇偶数的分界线,可以考虑填 i i i 2 i 2i 2i

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
int n,a[1005][1005],vis[1000005];
vector<int>v1,v2,v3,v4;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;
	if(n==3){
		cout<<"1 3 5\n8 6 9\n4 2 7";
		return 0;
	}
	if(n==4){
		cout<<"15 11 16 12\n13 3 6 9\n14 7 8 1\n4 2 10 5";
		return 0;
	}
	if(n%2==0){
		for(int i=1;i<=n;i++){
			a[n/2][i]=i*2+1;
			a[n/2+1][i]=i*4+2;
			vis[i*2+1]=vis[i*4+2]=1;
		}
		for(int i=1;i<=n*n;i++){
			if(!vis[i]){
				if(i%2)v1.pb(i);
				else v2.pb(i);
			}
		}for(int i=1;i<n/2;i++){
			for(int j=1;j<=n;j++){
				a[i][j]=v1.back();v1.pop_back();
			}
		}
		for(int i=n/2+2;i<=n;i++){
			for(int j=1;j<=n;j++){
				a[i][j]=v2.back();v2.pop_back();
			}
		}
	}
	else {
		a[n/2+1][n/2+1]=9,a[n/2][n/2]=3;
		a[n/2+1][n/2]=6,a[n/2+2][n/2+1]=18;
		vis[9]=vis[3]=vis[6]=vis[18]=1;
		for(int i=1;i<=n;i++){
			if(!vis[i*2+1])v3.pb(i*2+1),vis[i*2+1]=vis[i*4+2]=1;
		}
		for(int i=1;i<n/2;i++){
			a[n/2][i]=v3.back(),a[n/2+1][i]=v3.back()*2;v3.pop_back();
		}
		for(int i=n/2+2;i<=n;i++){
			a[n/2+1][i]=v3.back(),a[n/2+2][i]=v3.back()*2;v3.pop_back();
		}
		for(int i=1;i<=n*n;i++){
			if(!vis[i]){
				if(i%2)v1.pb(i);
				else v2.pb(i);
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(!a[i][j]){
					if(i<=n/2)a[i][j]=v1.back(),v1.pop_back();
					else a[i][j]=v2.back(),v2.pop_back();
				}
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout<<a[i][j]<<' ';
		}cout<<endl;
	}
}

Simultaneous Sugoroku

考场上根本没时间想。。。

对于起点是 1 ∼ 1 0 6 1\sim 10^6 1106的每个点,如果当前 x > 0 x>0 x>0那么往左走 d d d步,如果 x < 0 x<0 x<0那么往右走 d d d步,如果走到 0 0 0就停下来。

观察这个运动过程。如果某一时刻两个数移动到了 x x x − x -x x的位置,那么接下来他们的移动都是对称的,也就是说是一对相关性的点。

所以只维护原点左侧或右侧的点即可。复杂度 O ( m + max ⁡ ( w i ) ) O(m+\max(w_i)) O(m+max(wi))

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
int n,m,l=1,X[1000005],fa[1000005],res[1000005],mx[1000005];
deque<int>q;
void dfs(int x){
	if(~mx[x])return;dfs(fa[x]);
	if(mx[fa[x]])mx[x]=1,res[x]=res[fa[x]];
	else mx[x]=0,res[x]=-res[fa[x]];
}
int main(){
	cin>>n>>m;int tmp=0;for(int i=1;i<=n;i++)cin>>X[i],tmp=max(tmp,X[i]);memset(mx,-1,sizeof mx);
	for(int i=1;i<=tmp;i++)q.push_back(i);
	for(int i=1;i<=m;i++){
		int d;cin>>d;if(l>0)l-=d;else l+=d;
		int r=l+q.size()-1;
		if(l<=0&&r>=0){
			mx[q[abs(l)]]=1,res[q[abs(l)]]=i;
			if(abs(l)<=abs(r)){
				for(int j=0;j<abs(l);j++){
					fa[q[j]]=q[2*abs(l)-j];
				}for(int j=0;j<=abs(l);j++)q.pop_front();l=1;
			}
			else {
				for(int j=0;j<abs(r);j++){
					fa[q[q.size()-j-1]]=q[2*abs(l)-q.size()+j+1];
				}for(int j=0;j<=abs(r);j++)q.pop_back();
			}
		}
	}
	for(int i=0;i<q.size();i++){
		mx[q[i]]=0,res[q[i]]=l+i;
	}
	for(int i=1;i<=n;i++){
		dfs(X[i]);if(mx[X[i]])cout<<"Yes"<<' '<<res[X[i]]<<endl;
		else cout<<"No"<<' '<<res[X[i]]<<endl;
	}
} 

Sliding Window Sort

首先这个排序过程很不舒服

考虑将序列固定成每次只对前 m m m个数排序。每次排序完序列整体左移一位。

对于一个序列,我们可以把它看成两个部分,注意到前 m − 1 m-1 m1个数始终有序,并且每次会把最小的那个数弹出到序列末尾,而后 n − m + 1 n-m+1 nm+1个数始终在往前移位。

显然 K > n − m + 1 K>n-m+1 K>nm+1过后左右两部分的集合就不会发生变化了。考虑从最终序列右一半入手,记作 { x i } \{x_i\} {xi}。记初始序列 { a i } ( b i ) \{a_i\}(b_i) {ai}(bi)。注意到如果 x i − 1 > x i x_{i-1}>x_i xi1>xi那么 b i = x i b_i=x_i bi=xi

注意到忽略上述确定的值后 { x i } \{x_i\} {xi} { b i } \{b_i\} {bi}均为递增,问题转述为每次排序的 m m m个数中都有最小值 b i b_i bi,那么合法的 { a i } ( b i ) \{a_i\}(b_i) {ai}(bi)数目为 m l e n × ( m − 1 ) ! m^{len}\times (m-1)! mlen×(m1)

如果 K < n − m + 1 K<n-m+1 K<nm+1那么把多余的数删掉即可。

复杂度 O ( n ) O(n) O(n)

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
const int mod=998244353;
int n,m,K,a[600005];
ll fpow(ll x,ll y){
	ll z(1);
	for(;y;y>>=1){
		if(y&1)z=z*x%mod;
		x=x*x%mod;
	}return z;
}
int main(){
	cin>>n>>m>>K;
	for(int i=0;i<n;i++)cin>>a[i];
	if(K<n-m+1)n-=n-m+1-K;for(int i=0;i<n;i++)a[i+n]=a[i];
	vector<int>vec(a+K%n,a+K%n+n);K%=n-m+1;
	vector<int>vec2=vec;sort(vec2.begin(),vec2.end());
	for(auto &x:vec)x=lower_bound(vec2.begin(),vec2.end(),x)-vec2.begin()+1;
	for(int i=0;i<m-1;i++){
		if(vec[i]!=n-m+2+i){
			cout<<0;return 0;
		}
	}
	vec.erase(vec.begin(),vec.begin()+m-1);
	for(int i=0;i<n-m+1;i++)vec.pb(vec[i]);
	vector<int>vec3(vec.begin()+n-m+1-K,vec.begin()+n-m+1-K+n-m+1);
	int len=n-m+1,x=vec3[0];
	for(int i=1;i<vec3.size();i++){
		if(vec3[i]<x)len--;
		else x=vec3[i];
	}
	ll res=fpow(m,len);for(int i=1;i<=m-1;i++)res=res*i%mod;
	cout<<res;
} 

Rational Number System

咕咕咕。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值