Educational Codeforces Round 83 (Rated for Div. 2)

A水题


B.题意:重组该序列,使得对于任意ai-i!=aj-j
我们将a数组排序,从大到小。那么a1>=a2
也就有a1-1>a2-2。故从大到小输出即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t, n;
const int N = 1e2 + 10;
int a[N];
int main()
{
	t = read();
	while (t--)
	{
		n = read();
		upd(i, 1, n)a[i] = read();
		sort(a + 1, a + n + 1);
		dwd(i, n, 1)cout << a[i] << " ";
		cout << endl;
	}
	return 0;
}

c.
题意:第i此操作可以让选择任意一个位置,使得该位置变成vpos+ki。问v数组能否变成a数组。
我们明显发现,一个数字要能写成ki+ki+j+ki+k...........
故我们对于每一个a[i]进行进制拆分即可。如果有两个数字重复使用了同一个ki,那么无解。a[i]无法分解,无解。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
ll quick_pow(ll k, ll m)
{
	ll res = 1;
	while (m)
	{
		if (m & 1)res = res * k;
		k = k * k;
		m >>= 1;
	}
	return res;
}
int n, k, T;
ll a[40];
ll cnt[60];
map<ll, int>mp;
int main()
{
	T = read();
	while (T--)
	{
		n = read(), k = read();
		int ones = 0;
		mp.clear();
		memset(cnt, 0, sizeof(cnt));
		upd(i, 1, n) { a[i] = read(); if (a[i] == 1)ones++; }
		if (k == 1)
		{
			if (ones == 0 || ones == 1) {
				printf("YES\n");
				continue;
			}
			else
			{
				printf("NO\n");
				continue;
			}
		}
		else {
			cnt[0] = 1;
			upd(i, 1, 55)
			{
				cnt[i] = min((ll)1e16+1, 1ll * cnt[i - 1] * k);
			}
			bool flag = 0;
			upd(i, 1, n)
			{
				dwd(j, 55, 0)
				{
					if (a[i] >= cnt[j])
					{
						//cout << a[i] << endl;
						a[i] -= cnt[j];
						//cout <<j<<"  "<<a[i] <<" "<<cnt[j]<< endl;
						if (mp[j] == 0)mp[j] = 1;
						else {
							flag = 1;
						}
					}
				}
				if (a[i] != 0)
				{
					flag = 1;
				}
			}
			if(flag==0)
			{
				printf("YES\n");
			}
			else printf("NO\n");
		}
	}
	return 0;
}

D.
题意:构造一个序列,使得序列先单增后单减,并且这个序列有且仅有一个数字相等。取值范围从1~m。长度为n。问取法。
因为序列有且仅有一个相等,那么相当于从m个里面取n-1个不同的数字出来,方案数\(C_{m}^{n-1}\),同时,我们要在这n-2个不同的数字里面选取一个数字,把他变成两个,即满足有且仅有一个相等,方案数:\(C_{n-2}^{1}\)(一共n-1个数字,去除最大值,最大值有且仅有一个不能相等。)
我们选出了该序列所需要的n个数字后,在序列中继续进行方案计算。相等的那个数字一定在max的左右两边,要不然不满足单调性。所以max能在的位置为2~n -1。当max在i位置的时候,左边出去相等的哪个数字外,一共需要 i-1个数字去填充,方案数\(C_{n-3}^{i-1}\),可以观察到,因为需要满足单调性而且左右两边的数字不相等,那么递增序列在每一种方案是固定的,即假设我们的数字是1 1 2 3 4
假设4在pos=3,有方案数\(C_{2}^{1}\),即1 2 4 3 1和1 3 4 2 1,每种情况固定。

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const int mod = 998244353;
ll quick_pow(ll a,ll k){
	ll res = 1;
	while(k){
		if(k&1)res=(res*a)%mod;
		a=(a*a)%mod;
		k>>=1;
	}
	return res;
}
ll inv(ll x){
	return quick_pow(x,mod-2);
}
ll jc(int x){
	ll res= 1;
	for(int i=1;i<=x;i++)res=(res*i)%mod;
	return res;
}
int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	if(n<3)return 0*printf("0\n"); 
	ll ans = 0;
	ll Mj=jc(m);
	ll MNj=jc(m-n+1);
	ll Nj=jc(n-1);
	ll C = (Mj * inv((MNj*Nj)%mod))%mod;
	ans= ((C*(n-2))%mod*quick_pow(2,n-3))%mod;
	printf("%lld\n",ans);
}

E.
题意:当a[i]a[i+1]的时候,可以相互合并,a[i]=a[i]+1,而且总长度减一。问最小长度。
区间dp。
令dp[i][j]表示i,j的最小距离。再令rt[i][j]表示当i,j区间都合并的时候,a[i]。
从区间长度开始枚举,有且仅有,dp[i][k]
1&&dp[k+1][j]==1&&rt[i][k]=rt[k+1][j]的时候,dp[i][j]=1,rt[i][j]=rt[i][k]+1。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 505;
int dp[N][N];
int rt[N][N];
int n;
int a[N];
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	//freopen("input.txt", "r", stdin);
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= n; i++) {
		for (int j = i; j <= n; j++) {
			if (i == j) {
				dp[i][j] = true;
				rt[i][j] = a[i];
			}
			else {
				dp[i][j] = j - i + 1;
			}
		}
	}
	for (int len = 2; len <= n; len++) {
		for (int i = 1; i + len - 1 <= n; i++) {
			int j = i + len - 1;
			for (int k = i; k < j; k++) {
				dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
				if (dp[i][k] == 1 && dp[k + 1][j] == 1 && rt[i][k] == rt[k + 1][j]) {
					dp[i][j] = 1;
					rt[i][j] = rt[i][k] + 1;
				}
			}
		}
	}
	cout << dp[1][n];
	return 0;
}
posted @ 2020-03-10 10:57  LORDXX  阅读(198)  评论(0编辑  收藏  举报