IME Starters Try-outs 2018 题解

IME Starters Try-outs 2018

Codeforces Gym三星场的训练,主要是为了保持稳定的输出~

简单地分析一下这场个人训练赛

  • 4min,A题AC
  • 然后觉得F可做,直接按层数的奇偶性分类WA11
  • D题一个裸的线段树施展了13min...
  • 用了4min写了F的树形DP
  • 11min搞定了G题。理解题意后就是一个插板问题了
  • 23min过了B,很多时间用在了读题上
  • 15min过了E,一个很裸的最大生成树

79min 6题


之后的题,难度稍微大了一点。

  • J题的做法:如果没有加密操作,Trie树可以解决问题。对于加密操作,我们可以施展时间魔法,每一次加密,时间戳T++,然后T时刻插入一个串或者查询一个串,我们可以让这个串时间倒流T,这样集合内的每个串都站在了同一起跑线上。问题也就可以通过Trie树解决了。

  • 用了35min,一开始一直想把加密拆成若干个置换群,然后对于所有查询,对每个置换群分别check.....然而并不好搞。

  • J题大部分时间都用在了想假算法上。代码比较顺利

  • I题的做法:n是一个循环节。所以有c/n个完整的循环,ans+=c/n,然后加上最后一个不完整的循环节对答案的贡献,我们找到关于x的方程kx%n=d的最小正整数解并与c%n比较大小即可。

kx%n=d
=> kx-ny=d
=> kx+n(-y)=d
x是可以通过exgcd求出的
  • I用了40分钟,一开始没看到n是质数....然后被EXGCD搞了....
  • C题用了28min,找到一组最优解后没有退出循环WA了一发(最优解未必唯一啊)
  • H题用了50min.....从读题到第一发提交之间用了24minnodnow变量之间typo了一下,就GG了。

在H和I的代码上,长时间卡顿,很卜啊!!!!

code


A

按题意模拟即可

#include <iostream>
using namespace std;
int n, x;
int main() {
    scanf("%d",&n);
    int ans=0,sum=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        sum+=x;
        if(sum<0) ans=max(ans,-sum);
    }
    cout<<ans<<endl;
}

B

背包+输出解

#include <iostream>
#include <vector>
using namespace std;
string str[1002]; int val[1002];
int kit, m;
int s[1002], w[1002];
int n, x;

int dp[1002][2002], pre[1002][2002];
int main() {
    scanf("%d%d",&kit,&m);
    for(int i=1;i<=m;i++) {
        cin>>str[i];
        scanf("%d",&val[i]);
    }
    dp[0][0]=1;
    for(int i=0;i<m;i++){
        for(int j=0;j<2002;j++){
            if(dp[i][j] == 0) continue;
            dp[i+1][j]=1, pre[i+1][j]=j;
            if(j<=1000) {
                dp[i+1][j+val[i+1]]=1, pre[i+1][j+val[i+1]]=j;
            }
        }
    }

    scanf("%d", &n);
    for(int i=1;i<=n;i++) {
        scanf("%d",&x);
        int need = (x+1)/2 - kit;
        int j=-1;
        for(j=need;j<2002;j++)
            if(dp[m][j] == 1)
                break;

        if (j==2002) {
            printf("-1
"); continue;
        }

        int now = m, weight = j;
        vector<int> ret;
        while(true) {
            if (now==0) break;
            int tmp = pre[now][weight];
            if (weight != tmp) ret.push_back(now);
            now --, weight = tmp;
        }
        cout << ret.size();
        for(int j=0;j<ret.size();j++) {
            cout << " " << str[ret[j]];
        }
        cout << endl;
    }
}

C

状压DP

#include <iostream>
#include <vector>
using namespace std;
const int INF = 1000000007;
int n,a;
struct Mat {
    char pix[22][22];
    void init() {
        for(int i=0;i<21;i++)
        for(int j=0;j<21;j++)
            pix[i][j]='0';
    }
    void read() {
        for(int i=0;i<21;i++)
        scanf("%s",pix[i]);
    }
} mat[22];
int dis(Mat A, Mat B) {
    int ans=0;
    for(int i=0;i<21;i++)
    for(int j=0;j<21;j++)
        if(A.pix[i][j]!=B.pix[i][j])
        ans++;
    return ans;
}
int d[22][22];
int dp[1<<19][19];
pair<int,int> pre[1<<19][19];
vector<int> result;
void print(int s, int pos) {
    if (s == 0) return;
    int fi = pre[s][pos].first;
    int se = pre[s][pos].second;
    if (fi == s) result.push_back(-1);
    else result.push_back(pos+1);
    print(fi, se);
}
int main() {
    scanf("%d%d",&n,&a);
    mat[n].init();
    for(int i=0;i<n;i++) mat[i].read();
    for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++)
        d[i][j] = dis(mat[i], mat[j]);
    
    for(int i=0;i<=n;i++)
        for(int j=0;j<(1<<n);j++)
            dp[j][i]=INF;

    dp[0][n] = 0;
    for(int S=0;S<(1<<n);S++) {
        for(int bit=0;bit<=n;bit++) {
            if(bit != n && ((S>>bit)&1) == 0) continue;
            if (dp[S][bit]+a < dp[S][n]) {
                dp[S][n]=dp[S][bit]+a;
                pre[S][n]=make_pair(S,bit);
            }
            for(int i=0;i<n;i++) {
                if ((S>>i)&1) continue;
                if (dp[S][bit] + d[bit][i] < dp[S|(1<<i)][i]) {
                    dp[S|(1<<i)][i] = dp[S][bit]+d[bit][i];
                    pre[S|(1<<i)][i] = make_pair(S, bit);
                }
            }
        }
    }
    int bst = INF;
    for(int i=0;i<n;i++) {
        if(dp[(1<<n)-1][i] < bst) bst = dp[(1<<n)-1][i];
    }
    for(int i=0;i<n;i++) {
        if(dp[(1<<n)-1][i]==bst) {
            printf("%d
", bst);
            print((1<<n)-1, i);
            break;
        }
    }
    for(int i=(int)result.size()-1;i>=0;i--) {
        if (result[i] == -1)
            printf("*
");
        else
            printf("%d
", result[i]);
    }
}

D

直接上线段树吧

#include <iostream>
using namespace std;
const int N = 100000+10;
double sum[N<<2],a[N];
void build(int l,int r,int rt) {
    if(l==r) {
        sum[rt]=a[l]; return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int l,int r,int rt,int pos,double x) {
    if(l==r) {
        sum[rt]+=x;return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) update(l,mid,rt<<1,pos,x);
    else update(mid+1,r,rt<<1|1,pos,x);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
double query(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R) return sum[rt];
    int mid=(l+r)>>1;
    double ans=0;
    if(L<=mid) ans+=query(l,mid,rt<<1,L,R);
    if(R >mid) ans+=query(mid+1,r,rt<<1|1,L,R);
    return ans;
}
int n;
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf",&a[i]);
    }
    build(1,n,1);
    int q; scanf("%d",&q);
    while(q--) {
        int op; scanf("%d",&op);
        if(op==1) {
            int pos; double x;
            scanf("%d%lf",&pos,&x);
            update(1,n,1,pos,x-a[pos]);
            a[pos]=x;
        } else {
            int l,r;scanf("%d%d",&l,&r);
            double s=query(1,n,1,l,r)/(r-l+1);
            printf("%.8f
", s);
        }
    }
}

E

最大生成树

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 2000000+10;
vector<int> g[N]; 
struct Edge {
    int u,v,w;
    bool operator < (const Edge & o) const {
        return w > o.w;
    }
} edge[N]; int tot=0;

int par[N], father[N];
int find(int x) {
    if (par[x]==-1) return x;
    return par[x]=find(par[x]);
}

int n;
void dfs(int u,int p) {
    father[u] = p;
    for(int i=0;i<g[u].size();i++) {
        int v=g[u][i]; if(v==p) continue;
        dfs(v, u);
    }
}
int main() {
    scanf("%d", &n);
    for(int i=2;i<=n;i++) {
        for(int j=1;j<i;j++) {
            int x;
            scanf("%d", &x);
            edge[++tot].u = i;
            edge[tot].v = j;
            edge[tot].w = x;
        }
    }
    sort(edge+1,edge+1+tot);
    for(int i=1;i<=n;i++) par[i]=-1;
    int cost = 0;
    for(int i=1;i<=tot;i++) {
        if (find(edge[i].u) != find(edge[i].v)) {
            g[edge[i].u].push_back(edge[i].v);
            g[edge[i].v].push_back(edge[i].u);
            cost += edge[i].w;
            par[find(edge[i].u)] = find(edge[i].v);
        }
    }
    dfs(1, -1);
    printf("%d
", cost);
    for(int i=2;i<=n;i++) {
        printf("%d
", father[i]);
    }
}
 

F

树形DP.

#include <iostream>
#include <vector>
using namespace std;
const int N = 100000+10;
vector<int> g[N];
int n,m;
int dp[N][2];

void dfs(int u,int p) {
    dp[u][0]=0;dp[u][1]=1;
    for(int i=0;i<g[u].size();i++) {
        int v=g[u][i];
        if(v==p) continue;
        dfs(v,u);
        dp[u][0]+=max(dp[v][0],dp[v][1]);
        dp[u][1]+=dp[v][0];
    }  
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) {
        int u,v;scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,-1);
    printf("%d
", max(dp[1][0],dp[1][1]));
}

G

排列组合+推公式

#include <iostream>
using namespace std;
typedef long long LL;
const int N = 300000+10;
const LL MOD = 1000000007;
LL f[N],p[N];
LL mpow(LL a,LL x){
    if(x==0) return 1;
    LL t=mpow(a,x>>1);
    if(x%2==0) return t*t%MOD;
    return t*t%MOD*a%MOD;
}
LL C(int x,int y) {
    LL ans=f[x];
    ans=ans*mpow(f[y],MOD-2)%MOD;
    ans=ans*mpow(f[x-y],MOD-2)%MOD;
    return ans;
}
int main() {
    f[0]=1,p[0]=1;
    for(int i=1;i<N;i++) {
        f[i]=f[i-1]*(LL)i%MOD;
        p[i]=p[i-1]*6LL%MOD;
    }
    int c,n;cin>>n>>c;
    LL ans=C(c-2*n,n)*p[n]%MOD*f[n]%MOD;
    printf("%lld
", ans);
}

H

最短路

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int N = 4000000+10;
const int INF = 1000000007;
vector< pair<int,int> > g[N];
int n,m,q;
int vis[N], dis[N];

struct Nod {
    int pos, flight, cost;
    bool operator < (const Nod & o) const {
        return cost > o.cost;
    }
};

int id(int pos,int cnt) {
    return pos * 1010 + cnt;
}

void dijkstra() {
    for(int i=0;i<N;i++) dis[i]=INF, vis[i]=0;
    dis[id(1,0)]=0;
    priority_queue<Nod> q;
    Nod nod; nod.pos=1,nod.flight=0,nod.cost=0;
    q.push(nod);

    while (q.size()) {
        Nod now = q.top(); q.pop();
        int u = id(now.pos, now.flight);
        if (vis[u]) continue;
        vis[u] = 1;
        for(int i=0;i<g[u].size();i++) {
            int v = g[u][i].first;
            if (vis[v] == 0 && dis[u]+g[u][i].second <= dis[v]) {
                dis[v] = dis[u] + g[u][i].second;
                nod.pos=v/1010, nod.flight=now.flight+1, nod.cost=dis[v];
                q.push(nod);
            }
        }
    }
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        for(int j=0;j<=1000;j++) {
            g[id(u,j)].push_back(make_pair(id(v,j+1), w));
            //g[id(v,j)].push_back(make_pair(id(u,j+1), w));
        }
    }
    dijkstra();
    int q; scanf("%d",&q);
    while(q--) {
        int d,k;
        scanf("%d%d",&d,&k);
        int res = INF; k++;
        for(int i=0;i<=k;i++) {
            if(dis[id(d,i)]<=res){
                res=dis[id(d,i)];
            }
        }
        if (res<10000000) {
            printf("=] %d
", res);
        } else {
            printf("=[
");
        }
    }

}

I

扩展欧几里得

#include <iostream>
using namespace std;
typedef long long LL;
int n, k, q;
LL exgcd(LL a, LL b, LL& x, LL& y)  {  
    if(!b) {  
        x = 1; y = 0; return a;  
    }  
    LL r = exgcd(b,a%b,y,x);  
    y -= a/b*x;  
    return r;  
}  
int main() {
    scanf("%d %d %d", &n, &k, &q);
    while (q --) {
        int c, d;
        scanf("%d %d", &c, &d);
        if (k%n==0) {
            if (d==0) printf("%d
", c);
            else printf("0
");
            continue;
        }
        int ans = c / n;
        int rem = c % n; // x [0, rem)
        // k*x + n*(-y) = d
        LL x, y;
        exgcd(k, n, x, y);
        x *= d;
        x = (x%n+n)%n;
        if (x<rem) ans++;
        printf("%d
", ans);
    }
}

J

#include <iostream>
using namespace std;
const int N = 500000+10;
int n,m;
char s[N];
int ch[N][30], size;
int T = 0;
void insert(char * s) {
    int now = 0;
    for(int i=0;s[i];i++) {
        int c=s[i]-'A';
        if (!ch[now][c]) {
            ch[now][c]=++size;
        }
        now=ch[now][c];
    }
}
bool match(char * s) {
    int now=0;
    for(int i=0;s[i];i++) {
        int c=s[i]-'A';
        if(!ch[now][c]) return false;
        now=ch[now][c];
    }
    return 1;
}
int nex[N], len[N], vis[N];
int cnt = 0;
void dfs(int u) {
    cnt ++; vis[u] = 1;
    if (vis[nex[u]] == 0) 
        dfs(nex[u]);
}
void init() {
    for(int i=0;s[i];i++) {
        nex[i] = s[i]-'A';
    }
    for(int i=0;i<n;i++) {
        if (vis[s[i]-'A']) continue;
        cnt = 0;
        dfs(s[i]-'A');
        int st = s[i]-'A';
        len[st] = cnt;
        int now = st;
        while(nex[now] != st) {
            now = nex[now];
            len[now] = cnt;
        }
    }
}

int main() {
    scanf("%d %d", &n, &m);
    scanf("%s", s);
    init();
    for(int i=1;i<=m;i++) {
        int op;
        scanf("%d", &op);
        if (op==1) {
            scanf("%s", s);
            for(int i=0;s[i];i++) {
                // shift -T
                int mv = (-T % len[s[i]-'A'] + len[s[i]-'A']) % len[s[i]-'A'];
                int now = s[i]-'A';
                while(mv --) now = nex[now];
                s[i] = 'A' + now;
            }
            insert(s);
        }
        if (op==2) {
            T ++;
        }
        if (op==3) {
            scanf("%s", s);
            for(int i=0;s[i];i++) {
                // shift -T
                int mv = (-T % len[s[i]-'A'] + len[s[i]-'A']) % len[s[i]-'A'];
                int now = s[i]-'A';
                while(mv --) now = nex[now];
                s[i] = 'A' + now;
            }
            if (match(s)) printf("YES
");
            else printf("NO
");            
        }
    }
}

原文地址:https://www.cnblogs.com/RUSH-D-CAT/p/9131518.html