Educational Codeforces Round 83 (Rated for Div. 2)补题

最近越打越菜,补题
Educational Codeforces Round 83 (Rated for Div. 2)

A. Two Regular Polygons

思路

没什么好说的,当 n n n能被 m m m整除的时候, m m m边形所有顶点一定可以与 n n n边形重合。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1000000007;
int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	#ifdef DEBUG
		freopen("input.in", "r", stdin);
	//	freopen("output.out", "w", stdout);
	#endif
	int t,n,m;
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		if(n%m)
			cout<<"NO"<<endl;
		else
			cout<<"YES"<<endl;
	}
	return 0;
}

B. Bogosort

题意

给你一个数组,排列元素,使得任意一对元素 a i a_i ai a j a_j aj i − a i ≠ j − a j i−a_i≠j− a_j iai=jaj。输出任一可行解即可。

思路

i < j i<j i<j时,如果令 a i ≥ a j a_i≥a_j aiaj的话,不等式一定成立,所以从大到小排序即可。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1000000007;
int a[maxn];
int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	#ifdef DEBUG
		freopen("input.in", "r", stdin);
	//	freopen("output.out", "w", stdout);
	#endif
	int t,n;
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)
			cin>>a[i];
		sort(a+1,a+n+1,greater<int>());
		for(int i=1;i<=n;i++)
			cout<<a[i]<<' ';
		cout<<endl;
	}
	return 0;
}

C. Adding Powers

题意

对于一个大小为 n n n的全0数组,能否进行以下操作,使得这个数组变为目标数组

  • i i i次操作时,可以对当前数组任意元素加上 k i k^i ki,或者跳过
  • 操作数 i i i 0 0 0开始计数

思路

贪心,对于目标数组的每一个元素 a i a_i ai,找到这个数用 k k k的幂之和的表示方法,如果其中一个幂使用了两次,则为NO;若出现其他元素使用过的幂,则也为NO。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1000000007;
ll a[maxn],rec[maxn];
int main()
{
	int t,n;
	cin>>t;
	while(t--)
	{
		map<ll,ll> mp;
		ll k;
		cin>>n>>k;
		for(int i=1;i<=n;i++)
			cin>>a[i];
		bool flag=1;
		for(int i=1;i<=n;i++)
		{
			while(a[i]>0)
			{
				ll now=1;
				while(now*k<=a[i])
					now*=k;
				if(mp[now])
				{
					flag=0;
					break;
				}
				mp[now]++;
				a[i]-=now;
			}
		}
		cout<<(flag?"YES":"NO")<<endl;
	}
	return 0;
}

D. Count the Arrays

题意

计算符合要求的数组的数量:

  1. 数组元素个数为 n n n
  2. 每个元素范围 [ 1 , m ] [1,m] [1,m]
  3. 数组内有且仅有一对元素相等
  4. 数组有一下标 i i i i i i及之前元素严格递增, i i i及其后元素严格递减。

思路

组合数学,套一个 L u c a s Lucas Lucas板子。

  1. m m m个数中挑出 n − 1 n-1 n1个数,最大的数作为中间塔顶。
  2. 剩下的 n − 2 n-2 n2个数挑出来一个,左右各分配一个。
  3. 其余的 n − 3 n-3 n3个元素每个有左/右两种可能

所以答案为:
C m n − 1 × ( n − 2 ) × 2 n − 3 C_m^{n-1}\times (n-2)\times 2^{n-3} Cmn1×(n2)×2n3

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5,inf=0x3f3f3f3f,mod=998244353;
//#define lowbit(x) ((x) & -(x))//<<setiosflags(ios::fixed)<<setprecision(9)
void read(){}
template<typename T,typename... T2>inline void read(T &x,T2 &... oth) {
	x=0; int ch=getchar(),f=0;
	while(ch<'0'||ch>'9'){if (ch=='-') f=1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	if(f)x=-x;
	read(oth...);
}
ll POW(ll a,ll b,ll p)
{
    ll ans = 1;
    while(b){
        if(b&1)
            ans = (ans%p*a%p) % p;
        a = (a%p*a%p) % p;
        b >>= 1;
    }
    return ans%p;
}
ll C(ll n,ll m,ll p)
{
    if(m > n)return 0;
    if(m == n)return 1;
    if(m > n - m)m = n - m;
    ll a = 1, b = 1 ;
    for(ll i = 0 ; i < m ; i++){
        a = a * (n - i) % p;
        b = b * (i + 1) % p;
    }
    return a * POW(b,p-2,p) % p;
}
ll lucas(ll n,ll m,ll p){//C(n,m)%p
    if(m == 0)
        return 1;
    return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}
int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	#ifdef DEBUG
		freopen("input.in", "r", stdin);
	//	freopen("output.out", "w", stdout);
	#endif
    ll n,m,ans=0;
    cin>>n>>m;
    if(n==2)
	{
		cout<<0<<endl;
		exit(0);
	}
	cout<<lucas(m,n-1,mod)*(n-2)%mod*POW(2,n-3,mod)%mod<<endl;
    return 0;
}

E. Array Shrinking

题意

一个长度为 n n n的数组 a a a,对于任一元素 a i a_i ai,若有 a i = a i + 1 a_i=a_{i+1} ai=ai+1,则可用 a i + 1 a_i+1 ai+1来替换这两个元素,求数组变化后的最小长度。

思路

读完题就感觉是区间DP,可惜我不会……
d p [ l ] [ r ] dp[l][r] dp[l][r]来表示区间 [ l , r ] [l,r] [l,r]合并后的值, d p [ l ] [ r ] = 0 dp[l][r]=0 dp[l][r]=0时说明这一区间无法连续合并。
f [ i ] f[i] f[i]表示到下标 i i i的合并后的最小长度。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=505,inf=0x3f3f3f3f,mod=1000000007;
//#define lowbit(x) ((x) & -(x))//<<setiosflags(ios::fixed)<<setprecision(9)
void read(){}
template<typename T,typename... T2>inline void read(T &x,T2 &... oth) {
	x=0; int ch=getchar(),f=0;
	while(ch<'0'||ch>'9'){if (ch=='-') f=1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	if(f)x=-x;
	read(oth...);
}
int dp[maxn][maxn],f[maxn];
int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	#ifdef DEBUG
		freopen("input.in", "r", stdin);
	//	freopen("output.out", "w", stdout);
	#endif
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>dp[i][i];
	for(int len=2;len<=n;len++)//长度
	{
		for(int l=1;l<=n;l++)//起点
		{
			int r=l+len-1;//终点
			if(r>n)
				break;
			for(int k=l;k<r;k++)//枚举分割点
			{
				if(dp[l][k]&&dp[l][k]==dp[k+1][r])
					dp[l][r]=dp[l][k]+1;
			}
		}
	}
	memset(f,inf,sizeof(f));
	f[0]=0;
	for(int i=1;i<=n;i++)
		for(int j=0;j<i;j++)
			if(dp[j+1][i])//j+1到i可以合成一块
				f[i]=min(f[i],f[j]+1);
	cout<<f[n]<<endl;
	return 0;
}

F、G估计不会,以后再补吧……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值