zoukankan      html  css  js  c++  java
  • 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
    ");            
            }
        }
    }
    
    
  • 相关阅读:
    请教visiouml活动图中动作状态和状态的区别谢谢 软件工程管理 软件规划版
    !!!IT人员迅速提升自我效率的十大方法
    如何在Visio的UML活动图中(判断及控制流)添加文字啊????
    Convert Standard String to System::String
    m_pRecordset遍历记录集之后,m_pRecordsetMoveFirst()为什么会出错
    !!! C++/CLI中使用using namespace System::Windows::Forms;+MessageBox报错最重要的是看MSDN 每个函数的使用例子
    !!!创建 UML 活动图 Visio Office_com
    C#反射之AssemblyCLR/c++可以通过反射调用c#类库
    请允许我进入你的世界
    以赛庆党日
  • 原文地址:https://www.cnblogs.com/RUSH-D-CAT/p/9131518.html
Copyright © 2011-2022 走看看