Educational Codeforces Round 17

Educational Codeforces Round 17

A. k-th divisor

水题,把所有因子找出来排序然后找第\(k\)

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
 
void solve(){
    LL n, k;
    cin >> n >> k;
    vector<LL> fac1;
    vector<LL> fac2;
    for(int i = 1; 1ll * i * i <= n; i++){
        if(n%i) continue;
        fac1.push_back(i);
        if(i!=n/i) fac2.push_back(n/i);
    }
    reverse(fac2.begin(),fac2.end());
    for(LL x : fac2) fac1.push_back(x);
    if(k>fac1.size()) cout << -1 << endl;
    else cout << fac1[k-1] << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    // int tt; for(scanf("%d",&tt); tt--; solve());
    solve();
    return 0;
}

B. USB vs. PS/2

显然先把两种独立的能配的尽量给配了,最后再去配都适配的

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
void solve(){
    static int a, b, c;
    vector<int> v1, v2;
    ____();
    cin >> a >> b >> c;
    int n; cin >> n;
    for(int i = 1; i <= n; i++){
        int x; string s;
        cin >> x >> s;
        if(s[0]=='U') v1.push_back(x);
        else v2.push_back(x);
    }
    sort(v1.begin(),v1.end());
    sort(v2.begin(),v2.end());
    int ptr1 = 0, ptr2 = 0;
    int cnt = 0;
    LL ret = 0;
    while(ptr1<v1.size() and a){
        ret += v1[ptr1++];
        a--;
        cnt++;
    }
    while(ptr2<v2.size() and b){
        ret += v2[ptr2++];
        b--;
        cnt++;
    }
    while(c){
        if(ptr1==v1.size() and ptr2==v2.size()) break;
        c--; cnt++;
        if(ptr1==v1.size()) ret += v2[ptr2++];
        else if(ptr2==v2.size()) ret += v1[ptr1++];
        else if(v1[ptr1]<v2[ptr2]) ret += v1[ptr1++];
        else ret += v2[ptr2++];
    }
    cout << cnt << ' ' << ret << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

C. Two strings

显然\(b\)串需要删掉中间的部分,也就是保留前缀和后缀
记一下\(b\)串前面能保留\(x\)个的情况下在\(a\)串中的最后匹配位置和\(a\)串后面还有\(x\)个位置的情况下最多能匹配\(b\)串的后缀长度
注意合并了之后串长不能超过\(a\)串或者\(b\)串的长度

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+8;

char s1[MAXN], s2[MAXN];
int nxt[MAXN][26], n, m, pos[MAXN], rpos[MAXN];
void solve(){
    cin >> s1+1 >> s2+1;
    n = strlen(s1 + 1);
    m = strlen(s2 + 1);
    for(int i = 0; i < 26; i++) nxt[n][i] = MAXN;
    for(int i = n - 1; i >= 0; i--){
        for(int j = 0; j < 26; j++) nxt[i][j] = nxt[i+1][j];
        nxt[i][s1[i+1]-'a'] = i + 1;
    }
    for(int i = 1; i <= n; i++) pos[i] = MAXN;
    int ptr = 0, now = 1;
    while(now <= m and nxt[ptr][s2[now]-'a']!=MAXN){
        ptr = nxt[ptr][s2[now]-'a'];
        pos[now] = ptr;
        now++;
    }
    reverse(s1+1,s1+1+n);
    reverse(s2+1,s2+1+m);
    for(int i = 0; i < 26; i++) nxt[n][i] = MAXN;
    for(int i = n - 1; i >= 0; i--){
        for(int j = 0; j < 26; j++) nxt[i][j] = nxt[i+1][j];
        nxt[i][s1[i+1]-'a'] = i + 1;
    }
    ptr = 0, now = 1;
    while(now <= m and nxt[ptr][s2[now]-'a']!=MAXN){
        ptr = nxt[ptr][s2[now]-'a'];
        rpos[n-ptr+1] = now;
        now++;
    }
    for(int i = n; i >= 0; i--) rpos[i] = max(rpos[i],rpos[i+1]);
    int maxx = 0, ps = -1;
    for(int i = 0; i <= m; i++){
        if(pos[i]==MAXN) break;
        if(i+rpos[pos[i]+1]>=maxx){
            maxx = i + rpos[pos[i]+1];
            ps = i;
        }
    }
    if(maxx==0) cout << "-" << endl;
    else{
        string a, b;
        int rmatch = rpos[pos[ps]+1];
        b = string(s2+1,s2+1+rmatch);
        reverse(s2+1,s2+1+m);
        a = string(s2+1,s2+1+ps);
        reverse(b.begin(),b.end());
        if(maxx>=m){
           if(maxx<=n) cout << s2 + 1 << endl;
            else cout << string(s2+1,s2+1+n) << endl;
        }
        else{
            if(maxx<=n) cout << a + b << endl;
            else cout << a + string(b.begin()+b.size()+a.size()-maxx,b.end()) << endl;
        }
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    // int tt; for(scanf("%d",&tt); tt--; solve());
    solve();
    return 0;
}

D. Maximum path

如果又往右走又往左走很麻烦,其实可以发现,连续往右走大于两步的情况都可以被分解成小于等于两步的走法,转移即可

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+7;
typedef long long int LL;
int n, A[4][MAXN];
LL f[4][MAXN];
inline void cmax(LL &x, LL y){ x = x > y ? x : y; }
void solve(){
    scanf("%d",&n);
    memset(f,-0x3f,sizeof(f));
    for(int i = 1; i <= 3; i++) for(int j = 1; j <= n; j++) scanf("%d",&A[i][j]);
    f[1][1] = A[1][1]; f[2][1] = f[1][1] + A[2][1]; f[3][1] = f[2][1] + A[3][1];
    f[3][2] = 0ll + A[1][1] + A[1][2] + A[2][2] + A[2][1] + A[3][1] + A[3][2];
    for(int i = 1; i < n; i++){
        cmax(f[2][i+1],f[2][i] + A[2][i+1]);
        cmax(f[1][i+1],f[1][i] + A[1][i+1]);
        cmax(f[3][i+1],f[3][i] + A[3][i+1]);
        cmax(f[2][i+1],f[1][i] + A[1][i+1] + A[2][i+1]);
        cmax(f[2][i+1],f[3][i] + A[3][i+1] + A[2][i+1]);
        cmax(f[1][i+1],f[2][i] + A[2][i+1] + A[1][i+1]);
        cmax(f[3][i+1],f[2][i] + A[2][i+1] + A[3][i+1]);
        cmax(f[1][i+1],f[3][i] + A[3][i+1] + A[2][i+1] + A[1][i+1]);
        cmax(f[3][i+1],f[1][i] + A[1][i+1] + A[2][i+1] + A[3][i+1]);
        if(i + 2 > n) continue;
        cmax(f[1][i+2],f[3][i] + A[3][i+1] + A[3][i+2] + A[2][i+2] + A[2][i+1] + A[1][i+1] + A[1][i+2]);
        cmax(f[3][i+2],f[1][i] + A[1][i+1] + A[1][i+2] + A[2][i+2] + A[2][i+1] + A[3][i+1] + A[3][i+2]);
    }
    cout << f[3][n] << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

E. Radio stations

因为两个接触的距离限制中半径要取\(\min\),所以考虑按半径大到小排序,把所有位置离散化一下,由于\(k\le 10\)然后每次只需要找对应的频率区间在可影响范围内有多少点即可,然后每次再把枚举的点放到对应的线段树里去
这里考虑动态开点权值线段树来做

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 5e5+7;


vector<int> vec;
int n, k;
pair<pair<int,int>,int> sta[MAXN];
struct segtree{
    int root[MAXN], sum[MAXN<<5], ls[MAXN<<5], rs[MAXN<<5], tot;
    #define pushup(rt) sum[rt] = sum[ls[rt]] + sum[rs[rt]]
    void modify(int l, int r, int pos, int &rt){
        if(!rt) rt = ++tot;
        sum[rt] += 1;
        if(l+1==r) return;
        int mid = (l + r) >> 1;
        if(pos<mid) modify(l,mid,pos,ls[rt]);
        else modify(mid,r,pos,rs[rt]);
    }
    int Q(int L, int R, int l, int r, int rt){
        if(L>=r or l>=R) return 0;
        if(L<=l and r<=R) return sum[rt];
        int mid = (l + r) >> 1;
        return Q(L,R,l,mid,ls[rt]) + Q(L,R,mid,r,rs[rt]);
    }
}ST;
int exc(int x){ return lower_bound(vec.begin(),vec.end(),x) - vec.begin() + 1; }
void solve(){
    scanf("%d %d",&n,&k);
    for(int i = 1; i <= n; i++){
        scanf("%d %d %d",&sta[i].first.first,&sta[i].second,&sta[i].first.second);
        vec.push_back(sta[i].first.first-sta[i].second);
        vec.push_back(sta[i].first.first+sta[i].second);
        vec.push_back(sta[i].first.first);
    }
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    sort(sta+1,sta+1+n,[](const pair<pair<int,int>,int> &A, const pair<pair<int,int>,int> &B){
        return A.second > B.second;
    });
    long long int ret = 0;
    for(int i = 1; i <= n; i++){
        int p = exc(sta[i].first.first);
        int l = exc(sta[i].first.first-sta[i].second);
        int r = exc(sta[i].first.first+sta[i].second);
        for(int f = max(1,sta[i].first.second-k); f <= sta[i].first.second+k; f++) ret += ST.Q(l,r+1,1,MAXN,ST.root[f]);
        ST.modify(1,MAXN,p,ST.root[sta[i].first.second]);
    }
    cout << ret << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    solve();
    return 0;
}

F. Tree nesting

在大树里面找小树,大树随意定根,接下来我们枚举小树的根,如果某个小树和之前枚举的同构了就直接跳过同构当然用树哈希来判断,,然后用小树和大树匹配,令\(f[i][j]\)表示大树的节点\(i\)和小树的节点\(v\)匹配的方案数,接下来我们对小树\(dfs\)一遍,每次枚举和当且节点匹配的大树节点
当当前点是小树的叶子节点石,方案数显然是\(1\)
否则考虑状压\(DP\)转移,假设当前石小树的\(u\)节点和大树的\(x\)节点匹配,那么找出两者所有的儿子,然后\(dp[i][msk]\)表示当前枚举到\(x\)的第\(i\)个儿子,当前已经匹配的\(u\)的子节点集合为\(msk\)的方案数,转移很好转,如果\(u\)的子节点有同构又要除掉阶乘,否则会有重复计算

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1111;
const int MOD = 1e9+7;
vector<int> GS[MAXN], GT[MAXN];
int n, m, fac[20], inv[20], rfac[20], prime[] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41};
int ret, sz[20], hax[20], fas[MAXN], fat[20];
set<int> vishash;
void dfss(int u, int par){
    fas[u] = par;
    for(int v : GS[u]) if(v!=par) dfss(v,u);
}
void dfs(int u, int par){
    sz[u] = hax[u] = 1;
    fat[u] = par;
    for(int v : GT[u]){
        if(v==par) continue;
        dfs(v,u);
        sz[u] += sz[v];
        hax[u] = (hax[u] + hax[v] * prime[sz[v]]) % MOD;
    }
}
int f[20][MAXN];
void match(int u){
    for(int v : GT[u]) if(v!=fat[u]) match(v);
    if((GT[u].size()==1 and fat[u]) or GT[u].empty()){
        for(int i = 1; i <= n; i++) f[u][i] = 1;
        return;
    }
    vector<int> sont;
    map<int,int> cnt;
    for(int v : GT[u]) if(v!=fat[u]){
        sont.push_back(v);
        cnt[hax[v]]++;
    }
    int ff = 1;
    for(auto p : cnt) ff = (1ll * ff * rfac[p.second]) % MOD;
    for(int x = 1; x <= n; x++){
        // try match u and x
        vector<int> sons;
        for(int v : GS[x]) if(v!=fas[x]) sons.push_back(v);
        vector<vector<int> > dp(2,vector<int>(1<<sont.size()));
        dp[0][0] = 1; int tag = 1;
        for(int i = 0; i < (int)sons.size(); i++, tag ^= 1){
            dp[tag] = dp[tag^1];
            for(int msk = 0; msk < (1<<sont.size()); msk++){
                for(int bit = 0; bit < (int)sont.size(); bit++){
                    if(msk>>bit&1) continue;
                    dp[tag][msk|(1<<bit)] = (dp[tag][msk|(1<<bit)] + 1ll * dp[tag^1][msk] * f[sont[bit]][sons[i]]) % MOD;
                }
            }
        }
        f[u][x] = 1ll * dp[tag^1][(1<<sont.size())-1] * ff % MOD;
    }
}
void test(int id){
    dfs(id,0);
    if(vishash.count(hax[id])) return;
    vishash.insert(hax[id]);
    memset(f,0,sizeof(f));
    match(id);
    for(int i = 1; i <= n; i++) ret = (ret + f[id][i]) % MOD;
}
void solve(){
    scanf("%d",&n);
    for(int i = 1; i < n; i++){
        int u, v; scanf("%d %d",&u,&v);
        GS[u].push_back(v);
        GS[v].push_back(u);
    }
    scanf("%d",&m);
    for(int i = 1; i < m; i++){
        int u, v; scanf("%d %d",&u,&v);
        GT[u].push_back(v);
        GT[v].push_back(u);
    }
    dfss(1,0);
    for(int i = 1; i <= m; i++) test(i);
    cout << ret << endl;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("Local.in","r",stdin);
    freopen("ans.out","w",stdout);
    #endif
    fac[0] = rfac[0] = inv[1] = 1;
    for(int i = 1; i < 20; i++) fac[i] = 1ll * i * fac[i-1] % MOD;
    for(int i = 2; i < 20; i++) inv[i] = 1ll * (MOD - MOD / i) * inv[MOD%i] % MOD;
    for(int i = 1; i < 20; i++) rfac[i] = 1ll * inv[i] * rfac[i-1] % MOD;
    solve();
    return 0;
}
posted @ 2020-08-16 00:15  _kiko  阅读(136)  评论(0编辑  收藏  举报