Harbour.Space Scholarship Contest 2023-2024 (Div. 1 + Div. 2) 简单题解

A.Increasing and Decreasing

题意:给定三个数字 x , y , n x,y,n x,y,n。要求去构造一个数组a,满足
a 1 = x , a n = y a_1=x,a_n=y a1=x,an=y
a 1 < a 2 < ⋯ < a n a_1<a_2< \cdots<a_n a1<a2<<an
b i = a i + 1 − a i , b 1 > b 2 > ⋯ > b n b_i=a_{i+1}-a_i,b_1>b_2> \cdots>b_n bi=ai+1ai,b1>b2>>bn

思路:从后往前去, − 1 , − 2 , − 3 -1,-2,-3 1,2,3,构造即可,最后如果 a 1 < x a_1<x a1<x那么则无法构造出来,反之 a 1 = x a_1=x a1=x是满足要求的

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=1005;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
struct graph{
	int cnte,hd[N];
	struct  edge{
		int v,nt;
	}e[N<<1];
	void addedge(int v,int u){
		e[++cnte].v=u;
		e[cnte].nt=hd[v];
		hd[v]=cnte;
	}
};
int x,y,n,a[N]; 
void solve(){
	cin>>x>>y>>n;
	a[n]=y;
	for(int j=1,i=n-1;i>=1;i--,j++){
		a[i]=a[i+1]-j;
	}
	if(a[1]>=x){
		a[1]=x;
		for(int i=1;i<=n;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;
	}else{
		cout<<-1<<endl;
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}

}

B. Swap and Reverse

题意:给定长度为 n n n的字符串s和一个正整数 k k k可以进行以下两个操作任意次
1.交换 s i , s i + 2 s_i,s_{i+2} si,si+2的位置
2.反转长度为 k k k的任意连续子串
求可以达到的字典序最小的字符串

思路:只进行操作一的话,奇数位置上的字母和偶数位置上的是独立的,操作二在 k k k为偶数的情况下可以将奇偶位置联合,奇数则无效果。
如果 k % 2 = 0 k\%2=0 k%2=0则排序输出
反之
奇数位置排序,偶数位置排序,奇偶位置不变输出

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=1005;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
struct graph{
	int cnte,hd[N];
	struct  edge{
		int v,nt;
	}e[N<<1];
	void addedge(int v,int u){
		e[++cnte].v=u;
		e[cnte].nt=hd[v];
		hd[v]=cnte;
	}
};
int n,k;
string s; 
void solve(){
	cin>>n>>k;
	cin>>s;
	if(k%2==0){
		sort(s.begin(),s.end());
		cout<<s<<endl;
	}else{
		vector<char>c[2];
		for(int i=0;i<n;i++){
			c[i%2].push_back(s[i]);
		}
		sort(c[0].begin(),c[0].end());
		sort(c[1].begin(),c[1].end());
		for(int i=0;i<n;i++){
			if(i%2==0){
				cout<<c[0][i/2];
			}else{
				cout<<c[1][i/2];
			}
		}
		cout<<endl;
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}

}

C. Divisor Chain

题意:给定一个整数 x x x,通过不大于1000次操作后变成1。
每次可以选择 x x x的一个因素 d d d,将 x : = x − d x:=x-d x:=xd,相同的 d d d至多选择两次。
(写的很奇怪调了一万年)
思路:考虑每个数字的二进制状态,如果是形如 10000...000 10000...000 10000...000的状态每次减去自身的一半,那么一定等变成1。
如果不是上面的状态那么我们需要变成上面的状态。
考虑减去每个数字的 l o w b i t lowbit lowbit,因为 l o w b i t ( x ) lowbit(x) lowbit(x)一定是 x x x的因数,这样减去第一个1后面的所有的1可以达到2的次幂的状态。
所有的因数被选择不会超过两次,操作的次数不会超过60次
(那如果要求操作次数最小怎么办?)

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=0;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
struct graph{
	int cnte,hd[N];
	struct  edge{
		int v,nt;
	}e[N<<1];
	void addedge(int v,int u){
		e[++cnte].v=u;
		e[cnte].nt=hd[v];
		hd[v]=cnte;
	}
};
int lowbit(int x){
	return x&(-x);
}
int x;
void solve(){
	cin>>x;
	vector<int>ans;
	ans.push_back(x);
	while(x>1){
		if(lowbit(x)==x){
			x-=x/2;	
		}else{
			x-=lowbit(x);
		}
		ans.push_back(x);
	}
	cout<<ans.size()<<endl;
	for(int v:ans){
		cout<<v<<" ";
	}
	cout<<endl;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}

}

D. Matrix Cascade

题意:给定n*n的01矩阵,可以反转任意的位置(由0变1,由1变0),如果(x,y)被反转,那么所有 x − i ≥ ∣ y − j ∣ x-i\geq|y-j| xiyj的位置也被反转。求将所有位置都变成0的最小操作数。
(一眼题,还是调了一万年)
思路:很明显,一个点只会被上面或自身的操作影响,那么操作次数就是一定的了。快速维护每个点当前的01状态即可。
每个点的01状态由自身的初始值和其被操作的次数的奇偶确定。
考虑维护两个斜线的前缀和,形如:
5 4 3 2 1
6 5 4 3 2
7 6 5 4 3
8 7 6 5 4
9 8 7 6 5

9 8 7 6 5
8 7 6 5 4
7 6 5 4 3
6 5 4 3 2
5 4 3 2 1
设上区域内被操作的次数的和为A
设下区域内被操作的次数的和为B
那么当前这个点被操作的次数为A-B
树状数组维护单点修改,和单点查询即可。
复杂度为 O ( n 2 l o g ( n ) ) O(n^2log(n)) O(n2log(n))

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=3005;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
struct graph{
	int cnte,hd[N];
	struct  edge{
		int v,nt;
	}e[N<<1];
	void addedge(int v,int u){
		e[++cnte].v=u;
		e[cnte].nt=hd[v];
		hd[v]=cnte;
	}
};
struct bit{
	int n;
	vector<int>num;
	bit(int n):n(n),num(n+1,0){}//初始化 
	int lowbit(int x){
    	return x&(-x);
	}
	void add(int i,int v){    //在i位置加上k
    	while(i <= n){
        	num[i] += v;
        	i += lowbit(i);
    	}
	}
	int sum(int i){//求A[1 - i]的和
    	int res = 0;
    	while(i > 0){
        	res += num[i];
        	i -= lowbit(i);
    	}
    	return res;
	}
};
int n,op[N][N],opp[N];
string s[N];
int getida(int x,int y){
	return abs(x-1)+abs(n-y)+1;
}
int getidb(int x,int y){
	return abs(n-x)+abs(n-y)+1;
}
void solve(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>s[i];
	}
	bit A(n*2),B(n*2);
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int ida=getida(i,j);
			int idb=getidb(i,j);
			int op=A.sum(ida)-B.sum(idb-1);
//			cout<<i<<" "<<j<<" "<<op<<" "<<A.sum(ida)<<" "<<B.sum(idb)<<endl;
			if((op%2+(s[i-1][j-1]-'0'))%2){
				ans++;
				A.add(ida,1);
				B.add(idb,1);
			}
		}
	}
	cout<<ans<<endl; 
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
}

E. Guess Game

题意:给定一个长度为n的数组S,每次随机选两个数a和b,分别告诉Alice和Bob,再告诉他们这两个数子按位或的值,他们只能说“我不知道”或者“我知道”,直到确切的猜出 a < b , a > b , o r a = b a<b,a>b , or \quad a=b a<b,a>b,ora=b,求轮流次数的期望值。
(C,D花太多时间,还想得很奇怪遂寄)
一眼想到小时候看的一个国产动漫叫《端脑》,不同的是告诉俩人的是a*b,然后猜准确的值。但赛时没有AC。

思路:看到 0 ≤ s i < 2 30 0\leq s_i <2^{30} 0si<230,和按位或应该就可以想到按位去判断。
(但是赛时没有)
考虑从高位向低位判断,考虑当前位置
如果是(0,0)
那么不需要询问,直接看下一位置。
如果是(0,1)
经过一轮判断出大小
如果是(1,0)
经过两轮判断出大小
如果是(1,1)
经过一轮可以判断出当前位相等,然后看下一位。
如果都相等,也就是所有位置都判断完成,则需要额外一次判断两者相等。
把所有数字插入字典树,然后挨个去询问即可
最后将得出的总数除以方案总数即使答案。

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=2e5+5;
const ll md=998244353;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
struct graph{
	int cnte,hd[N];
	struct  edge{
		int v,nt;
	}e[N<<1];
	void addedge(int v,int u){
		e[++cnte].v=u;
		e[cnte].nt=hd[v];
		hd[v]=cnte;
	}
};
int trie[N<<5][2],cnt=0;
ll val[N<<5];
ll n,s[N];
ll ksm(ll a,ll b){
	ll res=1;
	while(b){
		if(b&1)res=res*a%md;
		a=a*a%md;
		b>>=1;
	}
	return res;
}
ll getinv(ll a,ll b){
	return ksm(a,b-2);
}
void insert(int x){
	int now=0;
	for(int i=29;i>=0;i--){
		int wd=x>>i&1;
		if(!trie[now][wd]){
			trie[now][wd]=++cnt;
		}
		now=trie[now][wd];
		val[now]++;
	}
}
ll res=0;
void dfs(int x,int pos,int now){
//	cout<<x<<" "<<trie[x][0]<<" "<<trie[x][1]<<" "<<pos<<endl;
	if(pos<1){
//		cout<<"pos<1 "<<val[x]<<endl;
		res+=val[x];
		res%=md;
		return ;
	}
	int wd=now>>(pos-1)&1;
	if(wd){//1
		res=((res+2ll*val[trie[x][0]]%md)%md+1ll*val[trie[x][1]]%md)%md;
	}else{//0
		res=(res+1ll*val[trie[x][1]]%md)%md;
	}
//	cout<<"res up"<<endl;
	if(trie[x][1]&&wd){
		dfs(trie[x][1],pos-1,now);
	}
	if(trie[x][0]&&!wd){
		dfs(trie[x][0],pos-1,now);
	}
}
void solve(){
	cin>>n;
	for(int i=0;i<=n<<5;i++){
		trie[i][0]=trie[i][1]=0;
		val[i]=0;
	}
	res=0;
	for(int i=1;i<=n;i++){
		cin>>s[i];
		insert(s[i]);
	}
	for(int i=1;i<=n;i++){
		dfs(0,30,s[i]);
	}
//	cout<<res<<endl;
	ll ans=res*getinv(n*n%md,md)%md;
	cout<<ans<<endl;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
}

(持续补题。。。。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值