Codeforces Round #429 (Div. 2) 补题

时间:2022-07-19 06:25:31

A. Generous Kefa

题意:n个气球分给k个人,问每个人能否拿到的气球都不一样

解法:显然当某种气球的个数大于K的话,就GG了。

#include <bits/stdc++.h>
using namespace std;
int cnt[110];
char s[110];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
scanf("%s", s);
int len = strlen(s);
for(int i=0; i<len; i++){
cnt[s[i]-'A']++;
}
for(int i=0; i<110; i++){
if(cnt[i]>k){
puts("NO");
return 0;
}
}
puts("YES");
return 0;
}

B. Godsend

题意:两个玩一个小游戏,有一个序列,第一个人只能取走和为奇数的子序列,第二个只能取走和为偶数的子序列,谁不能移动谁就输了,问最后谁赢了。

解法:如果和为奇数的话,第一个取完直接赢,考虑和为偶数的,如果全是偶数第二个人赢,否则第一个人稳赢

#include <bits/stdc++.h>
using namespace std;
int n;
int a[1000010]; int main()
{
scanf("%d", &n);
long long sum = 0;
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
sum += a[i];
}
if(sum%2==1){
puts("First");
}
else{
int cnt = 0;
for(int i=1; i<=n; i++){
if(a[i]%2==1){
puts("First");
return 0;
}
}
puts("Second");
}
return 0;
}

C. Leha and Function

题意:定义F(n,k)表示1-n的排列里面选出k个不同的数的最小值,给了两个序列A,B,问如何安排A序列的顺序使得F(Ai',BI)的和的最大值。

解法:一个简单的贪心,就是N越大我们让K越小就好啦。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
int n;
struct node{
int x,id;
node(){}
node(int x, int id):x(x),id(id){}
}a[maxn],b[maxn];
bool cmp(node x, node y){
return x.x < y.x;
}
bool cmp2(node x, node y){
return x.x > y.x;
}
map <int,int> mp;
int aa[maxn];
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &a[i].x), a[i].id = i,aa[i]=a[i].x;
for(int i=1; i<=n; i++) scanf("%d", &b[i].x), b[i].id = i;
sort(a+1, a+n+1, cmp2);
sort(b+1, b+n+1, cmp);
for(int i=1; i<=n; i++){
mp[b[i].id] = a[i].id;
}
for(int i=1; i<=n; i++){
printf("%d ", aa[mp[i]]);
}
printf("\n");
return 0;
}

D. Leha and another game about graph

题意:给出一个连通图,并给每个点赋一个d值0或1或-1,要求选出一个边的集合,使得所有的点i要么d[i] == -1,要么dgree[i] % 2 == d[i],dgree[i]代表i结点的度数。

题解来源:http://blog.****.net/lxy767087094/article/details/77434503

解法:好题啊,当时没想出来,然后膜了一发题解的方法被惊艳到了。下面的描述来自上面博客:首先我们考虑一条边都不选的情况,此时所有d[i] == 0的i都满足了题目要求,此时如果有d[i] == 1的点,我们就要加一条边,我们考虑用dfs维护这个过程,在dfs序形成的搜索树上,若对于某个节点u,其子节点v有d[v] == 1,那么我们就将u和v之间的边的选取状态取反,即原来选变成不选,不选变成选,然后令d[v] = 0,代表该节点已经满足题意(你愿意赋值成其他值也无所谓,注意别弄混就行),若d[u] != -1,那么d[u]取反(因为u增加了一度,满足题意的状态肯定变化),可以发现,对于每个点,都能通过改变其和其父节点之间边的选取状态而改变其满足题意的状态,只有根节点没有父节点而例外,因此dfs完成后,如果根节点的状态为d[root] == 1,那么我们就要再选取一个d[i] == -1的结点i,将其到父节点的路径上所有边的选取状态取反,这样只会改变i和root结点的度数,路径上其他结点的度数并不受影响(因此满足题意的状态也不会改变),而对i来说度数改变是无所谓的,因此这样就只将d[root]变成了0。

那么什么时候输出-1呢,显然当不存在d[i] == -1的i并且d[root] == 1的时候,我们就无力回天了。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+5;
typedef pair<int,int> P;
vector <P> G[maxn];
P fa[maxn];
int n, m, node, d[maxn];
bool vis[maxn], select[maxn];
void dfs(int u){
int v, id;
vis[u] = 1;
for(int i=0; i<G[u].size(); i++){
v = G[u][i].first;
id = G[u][i].second;
if(vis[v]) continue;
fa[v] = make_pair(u, id);
dfs(v);
if(d[v] == 1){
d[v] = 0;
select[id] ^= 1;
if(d[u] != -1) d[u] ^= 1;
}
}
}
int main()
{
scanf("%d %d", &n,&m);
for(int i=1; i<=n; i++){
scanf("%d", &d[i]);
if(d[i]==-1) node=i;
}
for(int i=1; i<=m; i++){
int u, v;
scanf("%d %d", &u,&v);
G[u].emplace_back(v, i);
G[v].emplace_back(u, i);
}
dfs(1);
if(d[1] == 1){
if(node == 0){
puts("-1");
return 0;
}
while(node != 1){
select[fa[node].second] ^= 1;
node = fa[node].first;
}
}
int ans = 0;
for(int i=1; i<=m; i++){
if(select[i]) ans++;
}
printf("%d\n", ans);
for(int i=1; i<=m; i++){
if(select[i]){
printf("%d ", i);
}
}
printf("\n");
return 0;
}

E. On the Bench

题意:给出n个数,要求把他们重新排列之后,没有相邻的数的乘积是完全平方数

解法:从MPS的代码里学了一种容斥的方法:

Codeforces Round #429 (Div. 2) 补题

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 305;
const LL mod = 1e9+7;
LL dp[2][maxn];
LL C[maxn][maxn];
LL n, fac[maxn], Inv[maxn];
LL inv(LL a){
return a == 1 ? 1 : ((mod-mod/a)*inv(mod%a))%mod;
}
void pre_deal()
{
for(int i=0; i<=300; i++){
C[i][0]=1;
for(int j=1; j<=i; j++){
C[i][j] = C[i-1][j]+C[i-1][j-1];
if(C[i][j]>=mod) C[i][j]%=mod;
}
}
fac[0]=Inv[0]=1;
for(int i=1; i<=300; i++)
fac[i]=fac[i-1]*i%mod,Inv[i]=inv(fac[i]);
}
map <vector<LL>, LL> mp; int main()
{
pre_deal();
cin >> n;
for(int i=1; i<=n; i++){
LL x;
cin >> x;
vector <LL> v;
for(LL d=2; d*d<=x; d++){
if(x%d==0){
LL jud = 0;
while(x%d == 0) x/=d, jud^=1;
if(jud) v.push_back(d);
}
}
if(x>1) v.push_back(x);
mp[v]++;
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
LL now = 0, pre = 1;
for(auto it : mp){
LL cnt = it.second;
swap(now, pre);
memset(dp[now], 0, sizeof(dp[now]));
for(LL i=1; i<=n; i++){
for(LL j=1; j<=min(cnt,i); j++){
dp[now][i] += (dp[pre][i-j] * (((fac[cnt] * Inv[j])%mod * C[cnt-1][j-1])%mod))%mod;
if(dp[now][i]>=mod) dp[now][i]%=mod;
}
}
}
LL ans=0;
for(LL i=1; i<=n; i++){
ans += (((n-i&1)?(mod-1):1)%mod*fac[i]%mod)*dp[now][i]%mod;
if(ans>=mod) ans-=mod;
}
printf("%lld\n", ans);
return 0;
}