【AtCoder】ARC087

C - Good Sequence

题解

用个map愉悦一下就好了

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
int N;
int a[MAXN],ans;
map<int,int> zz;
void Init() {
    read(N);
    for(int i = 1 ; i <= N ; ++i) {read(a[i]);zz[a[i]] += 1;}
    sort(a + 1,a + N + 1);
    N = unique(a + 1,a + N + 1) - a - 1;
}
void Solve() {
    for(int i = 1 ; i <= N ; ++i) {
    if(zz[a[i]] < a[i]) ans += zz[a[i]];
    else ans += zz[a[i]] - a[i];
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
}

D - FT Robot

如果经过了奇数个T,那么原来在x轴上走,后来肯定在y轴上走,原来y轴变为x轴
如果偶数个T,那么保持原来的轴不变
我们会选定一个方向使得在这个方向上走后面的F的个数
这个可以用一个简单的背包(加上bitset优化一下)实现,注意在序列最前的F手动走完,因为无法改成X轴负方向

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
int N,x,y,s,t;
char str[8005];
vector<int> dir[2];
bitset<16005> f[2];
bool cmp(int a,int b) {
    return a > b;
}
void Solve() {
    scanf("%s",str + 1);read(x);read(y);
    N = strlen(str + 1);
    int d = 0;
    s = 0,t = 0;
    int p = 1;
    while(p <= N && str[p] == 'F') {++s;++p;}
    int cnt = 0;
    for(int i = p ; i <= N ; ++i) {
    if(str[i] == 'T') {
        if(cnt) dir[d].pb(cnt);
        d ^= 1;cnt = 0;
    }
    else {++cnt;}
    }
    if(cnt) dir[d].pb(cnt);
    if(abs(s - x) > N) {puts("No");return;}
    int cur = 0;
    f[cur].reset();
    f[cur][8000] = 1;
    for(auto k : dir[0]) {
    f[cur ^ 1].reset();
    f[cur ^ 1] = (f[cur] << k) | (f[cur] >> k);
    cur ^= 1;
    }
    if(!f[cur][8000 + abs(s - x)]) {puts("No");return;}
    cur = 0;
    f[cur].reset();
    f[cur][8000] = 1;
    for(auto k : dir[1]) {
    f[cur ^ 1].reset();
    f[cur ^ 1] = (f[cur] << k) | (f[cur] >> k);
    cur ^= 1;
    }
    if(!f[cur][8000 + abs(t - y)]) {puts("No");return;}
    puts("Yes");
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

E-Prefix-free Game

给每个可以走的点的sg函数简单推一下,从第(L - 1)层开始归纳
很容易发现sg函数是lowbit(L - dep)

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
int son[MAXN][2],N,rt = 1,Ncnt = 1;
int64 L,dep[MAXN];
char s[MAXN];
int64 lowbit(int64 x) {
    return x & -x;
}
void Insert(char *str) {
    int len = strlen(str + 1);
    int p = rt;
    for(int i = 1 ; i <= len ; ++i) {
    if(!son[p][str[i] - '0']) {
        son[p][str[i] - '0'] = ++Ncnt;
        dep[Ncnt] = dep[p] + 1;
    }
    p = son[p][str[i] - '0'];
    }
}
void Solve() {
    read(N);read(L);
    for(int i = 1 ; i <= N ; ++i) {
    scanf("%s",s + 1);
    Insert(s);
    }
    int64 ans = 0;
    for(int i = 1 ; i <= Ncnt ; ++i) {
    if((son[i][0] == 0 && son[i][1] != 0) || (son[i][0] != 0 && son[i][1] == 0)) {
        ans ^= lowbit(L - dep[i]);
    }
    }
    if(ans) puts("Alice");
    else puts("Bob");
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

F - Squirrel Migration

第一个结论就推不出来QAQ
就是考虑一条边,边断掉分成两个子树是\(x,y\),这条边最多被经过\(2min{siz[x],siz[y]}\)

考虑有两个重心(也就是断开一条边可以分成两个大小为\(N / 2\)的子树)
肯定可以构造合法的解,方案数就是\((\frac{N}{2}!)^2\)

有一个重心也是有解的,就是把所有的儿子从大到小排序
把最大的放在第一个,然后把剩下从小到大放,重心到它自己即可
这是一个合法解
那么我们可以知道,满足条件的答案一定是重心随便放,断掉重心后,剩下的点必须不选自己所在的树里的点

我们可以容斥做,用\(f[k]\)选了k个点,且这k个点能到达的点都是自己子树中的点,类似树背包那样转移
答案就是\(\sum_{i = 0}^{N - 1} (-1)^{i}f[i] \cdot (N - i)!\)

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 5005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
const int MOD = 1000000007;
int N;
struct node {
    int to,next;
}E[MAXN * 2];
int head[MAXN],sumE,siz[MAXN],son[MAXN];
int C[MAXN][MAXN],fac[MAXN],val[MAXN],tot,f[MAXN];
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
void add(int u,int v) {
    E[++sumE].next = head[u];
    E[sumE].to = v;
    head[u] = sumE;
}
void dfs(int u,int fa) {
    siz[u] = 1;
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(v != fa) {
        dfs(v,u);
        siz[u] += siz[v];
        son[u] = max(son[u],siz[v]);
    }
    }
    son[u] = max(son[u],N - siz[u]);
}
void Init() {
    read(N);
    int x,y;
    for(int i = 1 ; i < N ; ++i) {
    read(x);read(y);
    add(x,y);add(y,x);
    }
    C[0][0] = 1;
    for(int i = 1 ; i <= N ; ++i) {
    C[i][0] = 1;
    for(int j = 1 ; j <= N ; ++j) {
        C[i][j] = inc(C[i - 1][j],C[i - 1][j - 1]);
    }
    }
    fac[0] = 1;
    for(int i = 1 ; i <= N ; ++i) fac[i] = mul(fac[i - 1],i);
}
void Solve() {
    dfs(1,0);
    int g = 1;
    for(int i = 2 ; i <= N ; ++i) {
    if(son[i] < son[g]) g = i;
    }
    if(N % 2 == 0 && son[g] == N / 2) {
    out(mul(fac[N / 2],fac[N / 2]));enter;return;
    }
    for(int i = head[g] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(siz[v] < siz[g]) val[++tot] = siz[v];
    }
    if(g != 1) val[++tot] = N - siz[g];
    int s = 0;f[0] = 1;
    for(int i = 1 ; i <= tot ; ++i) {
    for(int t = s + val[i] ; t >= 0 ; --t) {
        for(int j = 1 ; j <= val[i] ; ++j) {
        if(j > t) break;
        f[t] = inc(f[t],mul(mul(f[t - j],C[val[i]][j]),mul(C[val[i]][j],fac[j])));
        }
    }
    s += val[i];
    }
    int t = 1,ans = 0;
    for(int i = 0 ; i <= N - 1; ++i) {
    ans = inc(ans,mul(mul(t,f[i]),fac[N - i]));
    t = mul(t,MOD - 1);
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
}

转载于:https://www.cnblogs.com/ivorysi/p/10171974.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值