Divide by Zero 2021 and Codeforces Round #714 (Div. 2) A-E题

A题: Array and Peaks


题意:

给定一个 n n n k k k,构造一个长度为 n n n的排列,使得排列有 k k k个峰
,满足一个数比它左右相邻的数都大的数就是峰。

题解:

先构造出一个上升的排列,即 1 − n 1-n 1n升序排列,然后发现,最优的构造方法是,从第二个数开始,每两个数交换便能产生一个峰,即1 3 2 5 4能构造出两个峰。那么只需要按照这种方法去构造,就可以了,特判最后不能构造完。

AC代码:
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define pi acos(-1.0)
#define rep(i,a,n)  for(int i=a;i<=n;i++)
#define pb push_back
const ll mod=1e9+7;
using namespace std;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b){ll ret=1; while(b){if(b&1)ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret;}
int t,n,k,ans[105];
int main(){
	//freopen("testdata.in","r",stdin);
	//freopen("testout.out","w",stdout);
	cin>>t;
	while(t--){
	cin>>n>>k;	
	rep(i,1,n)	ans[i]=i;
	for(int i=2;i<=n-1;i+=2){
	if(k){
	swap(ans[i],ans[i+1]);k--;	
	}else	break;	
	
	}
	if(!k)
	rep(i,1,n)	cout<<ans[i]<<" ";
	else		cout<<-1;
	cout<<"\n";
	}


	return 0;
}
/*

  */
 

B题:AND Sequences


题意:

给定 n n n个非负整数,如果满足对于任意i,满足 a 1 − a i a1-ai a1ai与运算等于 a i + 1 − a n ai+1-an ai+1an进行与运算,问满足这样的排列总共多少种?

题解:

考虑i等于1的时候,第一个数等于剩下的所有数进行&运算,那么说所有数&运算就应该等于第一个数,同理,可证i==n-1时也满足。那么说第一个数和最后一个数必须等于所有数&运算出来,先找出有多少个数满足等于所有数&起来,那么对于中间的数(2-(n-1)),就任意排列就可以了。

AC代码:
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define pi acos(-1.0)
#define rep(i,a,n)  for(int i=a;i<=n;i++)
#define pb push_back
const ll mod=1e9+7;
using namespace std;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b){ll ret=1; while(b){if(b&1)ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret;}
const int N=2e5+5;
int t,n;
ll a[N],ans,cnt,js,jc;
int main(){
	//freopen("testdata.in","r",stdin);
	//freopen("testout.out","w",stdout);
	cin>>t;
	while(t--){
	cin>>n;
	ans=0;js=0;jc=1;
	rep(i,1,n)	cin>>a[i];
	cnt=a[1];
	rep(i,2,n)	cnt&=a[i];
	rep(i,1,n)
	if(cnt==a[i])	js++;
	if(js<=1){
	cout<<0<<"\n";continue;	
	}
	for(ll i=1;i<=n-2;i++)	jc=jc*i%mod;
	ans=js*(js-1)%mod;
	ans=ans*jc%mod;
	cout<<ans<<"\n";
		
	}


	return 0;
}
/*

  */
 

C题:Add One


题解:

这题是纯找规律了, d p [ i ] dp[i] dp[i]表示0经过 i i i秒后能产生多少数?
dp[i]=dp[i-9]+dp[i-10]就可以了。

#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define pi acos(-1.0)
#define rep(i,a,n)  for(int i=a;i<=n;i++)
#define pb push_back
const ll mod=1e9+7;
using namespace std;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b){ll ret=1; while(b){if(b&1)ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret;}
const int N=3e5+100;
int t;
ll n,m,ans,a[15],dp[N];	
void init(){
	rep(i,0,9)	dp[i]=1;
	for(int i=10;i<N;i++){
	dp[i]=(dp[i-9]+dp[i-10])%mod;	
	}	
	
}
int main(){
	//freopen("testdata.in","r",stdin);
	//freopen("testout.out","w",stdout);
	init();
	cin>>t;
	while(t--){
	scanf("%lld %lld",&n,&m);ans=0;
	while(n){
	ll tmp=n%10;n/=10;
	ans=(ans+dp[m+tmp])%mod;
	}
	printf("%lld\n",ans);
	
	}


	return 0;
}
/*

  */


D题:GCD and MST

题解:

先从最小的点开始,以这个点为min时,向左右两边去找,如果左右两边的数是当前数的倍数,那么就存在这条边,然后并查集维护下,然后修改答案就可以了,初始化答案为p*(n-1)。详见代码

AC代码:
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define pi acos(-1.0)
#define rep(i,a,n)  for(int i=a;i<=n;i++)
#define pb push_back
const ll mod=1e9+7;
using namespace std;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b){ll ret=1; while(b){if(b&1)ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret;}
const int N=2e5+5;
int t;
ll n,vis[N],a[N],cnt,f[N];
ll p,ans;
struct node{
	int pos;
	ll a;
}b[N];
bool cmp(node a,node b){
	return a.a<b.a;
}
int find(int x){
	if(f[x]!=x)	f[x]=find(f[x]);
	return f[x];
}
void join(int x,int y){
	int xx=find(x);
	int yy=find(y);
	f[xx]=yy;
}
int main(){
	//freopen("testdata.in","r",stdin);
	//freopen("testout.out","w",stdout);
	cin>>t;
	while(t--){
	scanf("%d %lld",&n,&p);
	rep(i,1,n)	f[i]=i;
	ans=p*(n-1);cnt=n-1;
	rep(i,1,n)	vis[i]=0;
	rep(i,1,n)	scanf("%lld",&b[i].a);
	rep(i,1,n)	a[i]=b[i].a;
	rep(i,1,n)	b[i].pos=i; 
	sort(b+1,b+1+n,cmp);
	for(int i=1;i<=n;i++){
	if(b[i].a>=p)	break;
	ll l=b[i].pos,r=b[i].pos;
	while(l>=1&&!vis[l]){
	if(find(l)==find(b[i].pos)&&l!=b[i].pos)	break;	
	if(a[l]%a[b[i].pos]!=0)	break;
	join(l,b[i].pos);
	l--;	
	}l++;
	while(r<=n&&!vis[r]){
	if(find(r)==find(b[i].pos)&&r!=b[i].pos)	break;
	if(a[r]%a[b[i].pos]!=0)	break;
	join(r,b[i].pos);
	r++;	
	}r--;vis[b[i].pos]=1;
	ans-=(p-b[i].a)*min(r-l,cnt);
	cnt-=(r-l);
	if(cnt<=0)	break;	
	}	

	
	printf("%lld\n",ans);
	}


	return 0;
}
/*

  */


/*

  */


E题待补

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值