最近越打越菜,补题
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 i−ai=j−aj。输出任一可行解即可。
思路
当 i < j i<j i<j时,如果令 a i ≥ a j a_i≥a_j ai≥aj的话,不等式一定成立,所以从大到小排序即可。
代码
#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
题意
计算符合要求的数组的数量:
- 数组元素个数为 n n n
- 每个元素范围 [ 1 , m ] [1,m] [1,m]
- 数组内有且仅有一对元素相等
- 数组有一下标 i i i, i i i及之前元素严格递增, i i i及其后元素严格递减。
思路
组合数学,套一个 L u c a s Lucas Lucas板子。
- 在 m m m个数中挑出 n − 1 n-1 n−1个数,最大的数作为中间塔顶。
- 剩下的 n − 2 n-2 n−2个数挑出来一个,左右各分配一个。
- 其余的 n − 3 n-3 n−3个元素每个有左/右两种可能
所以答案为:
C
m
n
−
1
×
(
n
−
2
)
×
2
n
−
3
C_m^{n-1}\times (n-2)\times 2^{n-3}
Cmn−1×(n−2)×2n−3
代码
#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估计不会,以后再补吧……