• 2013520 训练赛后总结


    题目来源: 2012天津现场赛

    A, 背景为麻将的模拟题,按照要求模拟就好。

    B,sqrt(N)分解因子,然后暴力算即可

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    
    int sum(int x,int b){
        int res = 0;
        while(x){
            res += (x%b)*(x%b);
            x /= b;
        }
        return res;
    }
    char mp[50] = "0123456789ABCDEF";
    
    int main(){
        int n, m;
        while( scanf("%d%d", &n,&m) != EOF){
            int ans = 0;
            for(int i = 1; i*i <= n; i++){
                if( n%i == 0 ){    
                if( i*i == n ){
                    ans += sum(i,m);        
                }
                else{
                    ans += sum(i,m);
                    ans += sum(n/i,m);
                }
                }
            }
            int a[50], n1 = 0;
            while(ans){
                a[n1++] = ans%m;
                ans /= m;
            }
                
            for(int i = n1-1; i >= 0; i--){    
                printf("%c", mp[a[i]]);    
            } puts("");
        }
        return 0;
    }
    View Code

    C,dp( L, x, y ) 表示 前L-2位完全匹配,L-1,L分别为x,y的方案数, 然后转移有三类:

      L-1 / L / L+1,     三个都单独转,两个一起, 三个一起, 推一下就可以得到O(1)计算出来

      转移方程可以写成  dp( L+1, y1, z )  = Min{ dp(L, x, y ) + cost(三个变换)  }

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)<(b)?(a):(b)
    #define count Count
    const int N = 1010;
    int s[1005], e[1005];
    char str[1005], str2[1005];
    int n, dp[1005][11][11];
    const int INF = 0x3f3f3f3f;
    int c3[10][10][10][10][10][10];
    int c2[10][10][10][10];
    int c1[10][10];
    
    int count(int x1, int x2, int up) {
        if (up) {
            if (x2 >= x1) return x2 - x1;
            else return 10-(x1 - x2);
        } else {
            if (x2 <= x1) return x1 - x2;
            else return 10-(x2 - x1);
        }
    }
    int change1(int x1,int x2){
        return min( count(x1,x2,1), count(x1,x2,0) );
    }
    int change2(int x1,int x2,int y1,int y2){
        int x_up = count(x1,x2,1), y_up = count(y1,y2,1);
        int x_down = count(x1,x2,0), y_down = count(y1,y2,0);
        return min( max(x_up,y_up), max(x_down,y_down) ); 
    }
    int change3(int x1,int x2,int y1,int y2,int z1,int z2){
        int x_up = count(x1,x2,1), y_up = count(y1,y2,1), z_up = count(z1,z2,1);
        int x_down = count(x1,x2,0), y_down = count(y1,y2,0), z_down = count(z1,z2,0);
        int res = INF;
        if( y_up<=x_up && y_up<=z_up ) res = min(res,min(10+y_up,x_up+z_up-y_up));
        else res = min( res, max(x_up,max(y_up,z_up)) );
        if( y_down<=x_down && y_down<=z_down ) res = min(res,min(10+y_down,x_down+z_down-y_down));
        else res = min( res, max(x_down,max(y_down,z_down)));
    }
    
    int comp(int x1,int x2,int y1,int y2,int z1,int z2){
        int t = INF;
        t = min( t, c1[x1][x2] + c1[y1][y2] + c1[z1][z2] );
        t = min( t, c1[x1][x2] + c2[y1][y2][z1][z2] );
        t = min( t, c2[x1][x2][y1][y2] + c1[z1][z2] );
        t = min( t, c3[x1][x2][y1][y2][z1][z2] );
        //t = min( t, change1(x1,x2)+change1(y1,y2)+change1(z1,z2) );
        //t = min( t, change1(x1,x2)+change2(y1,y2,z1,z2) );
        //t = min( t, change2(x1,x2,y1,y2)+change1(z1,z2) );
        //t = min( t, change3(x1,x2,y1,y2,z1,z2) );
        return t;
    }
    void init(){
        for(int x1 = 0; x1 < 10; x1++){
            for(int x2 = 0; x2 < 10; x2++){
                c1[x1][x2] = change1(x1,x2);
                for(int y1 = 0; y1 < 10; y1++){
                    for(int y2 = 0; y2 < 10; y2++){
                        c2[x1][x2][y1][y2] = change2(x1,x2,y1,y2);
                        for(int z1 = 0; z1 < 10; z1++){
                            for(int z2 = 0; z2 < 10; z2++){
                                c3[x1][x2][y1][y2][z1][z2] = change3(x1,x2,y1,y2,z1,z2);    
                            }    
                        }
                    }    
                }
            }    
        }
    }
    void solve() {
        memset(dp,0x3f,sizeof(dp));
        for(int y = 0; y < 10; y++){
            dp[1][0][y] = change1(s[1],y);        
        }
        for(int L = 1; L < n; L++)
        {    
            for(int x = 0; x < 10; x++)
                for(int y = 0; y < 10; y++)    {
                    if( dp[L][x][y] == INF ) continue;
                    for(int y1 = 0; y1 < 10; y1++)
                        for(int z = 0; z < 10; z++){
                            int t = comp(x,e[L-1],y,y1,s[L+1],z );    
                            dp[L+1][y1][z] = min( dp[L+1][y1][z], dp[L][x][y] + t );        
                        }
                }
        } 
        
        printf("%d\n", dp[n][e[n-1]][e[n]] );
    }
    
    int main() {
    //    printf("(5,2,1) = %d, (2,2,1) = %d\n", change3(5,9,2,9,1,5), change3(2,9,2,9,1,5) );
        init();
        while (scanf("%s %s", str + 1, str2 + 1) != EOF) {
            n = strlen(str+1);
            s[0] = e[0] = 0;    
            for (int i = 1; i <= n; ++i) {
                s[i] = str[i] - '0';
                e[i] = str2[i] - '0';
            }
            solve();
        }
        return 0;
    }
    View Code

    D, N个点围成一圈, 每个点有个权值,可以修改: i变为 -Ai,  i-1与i+1位置+Ai, 不会捉。。。

    E. 第i个城市建加油站花费为 2^i, 比 (1,i-1)全部建加油站的和还大,可见,若i城市不建加油站而在 (1,i-1)这些位置多建一些这样更优。 那么我们可以最初令所有城市都建,然后从N到1开始尝试删除加油站,看是否合法。

      然后就是删除一个加油站判定问题, 因为未规定一个点只能走一次,要求长度最大为K, 那么当一个点从一个有加油站的城市出发,要么到有加油站的城市,或者到没有加油站的城市, 此时若全部点需要走到,并且能够回到1, 则必定在那些没有加油站的城市能够返回,那么此时从加油站的城市到非加油站的城市 路径长度必须要少于或等于 K/2,这样才能保证返回,另外 从有加油站的城市 到 有加油站的城市 则只要距离小于等于K即可。必定可以返回。 另外,我们假定这样一个结论: 所有非加油站城市 都能通过至少一个 加油站城市 到达。 因为若 从一个 加油站城市 经过 多个非加油站城市 再到 加油站城市, 其路径总长度必定小于等于K, 那么意味着 这两个加油站城市 直接距离必定小于等于K,意味着我们不需要通过 非加油站 城市到达 加油站城市。  所以我们能够通过 BFS,若是加油站城市则 入队,然后判定是否能够走到所有顶点至少一次。

    #include<cstdlib>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    using namespace std;
    
    const int N = 150;
    const int inf = 0x3f3f3f3f;
    struct node{
        int x, y;
    }city[N];
    
    int mp[N][N];
    bool vis[N], sta[N];
    int n, K;
    
    int dist(int i,int j){
        return ceil( sqrt( (city[i].x-city[j].x)*(city[i].x-city[j].x)+(city[i].y-city[j].y)*(city[i].y-city[j].y) ) );
    }
    bool legal(){
        queue<int>Q; while( !Q.empty() ) Q.pop();
        memset(vis,0,sizeof(vis));
        Q.push(0);
        vis[0] = true;
        while( !Q.empty() ){
            int cur = Q.front(); Q.pop();
            for(int nxt = 0; nxt < n; nxt++){
                if( cur == nxt ) continue;
                if( !vis[nxt] ){
                    if( sta[nxt] ){
                        if( mp[cur][nxt] <= K )
                            vis[nxt] = true, Q.push(nxt);
                    }    
                    else{
                        if( mp[cur][nxt] <= K/2 ) 
                            vis[nxt] = true;
                    }
                }
            }
        }
        for(int i = 0; i < n; i++)
            if( !vis[i] ) return false;
        return true;
    }
    int main(){
        while( scanf("%d%d",&n,&K) != EOF){
            for(int i = 0; i < n; i++){
                scanf("%d%d", &city[i].x, &city[i].y );
            }    
            for(int i = 0; i < n; i++)
                for(int j = i; j < n; j++){
                    if( i == j ) mp[i][j] = inf;
                    else mp[i][j]=mp[j][i]=dist(i,j);
                }
            for(int i = 0; i < n; i++) sta[i] = true;
            if( legal() == false ){ puts("-1"); continue; }
            else{
                for(int i = n-1; i > 0; i-- ){
                    sta[i] = false;
                    if( !legal() ) sta[i] = true;
                }    
            }
            int k;    
            for(k = n-1; k > 0; k--) 
                if( sta[k] ) break;
            for( ; k >= 0; k-- )
                printf("%d",sta[k]);
            puts("");
        }    
        return 0;
    }
    View Code

    F.  所有字串问题,听说后缀数组能做,用后缀自动机写会方便。果断去学习下。。。。

    G. swap, 依据定义神码是 cup,  虽然矩阵很小,但是还是不知道如何计算。

    H.  对于AB顺序,求出X获得 A,B,A+B分的期望, 与 BA顺序,获得A,B,A+B的期望,比较下即可。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    const double esp = 1e-8;
    double sign(double x){
        return x<-esp?-1:(x>esp);
    }
    int main(){
        int T;
        scanf("%d", &T);
        while( T-- ){
            int A, B;
            double P, Q;
            scanf("%d%d%lf%lf", &A,&B,&P,&Q);
            double P1 = 1-P, Q1 = 1-Q;    
            double tiger = A*( Q1+Q*P*P1 )+B*(Q*P*P1)+(A+B)*(Q*P*P); 
            double wolf = A*(Q1*P1*P) + B*(Q+Q1*P*P1) + (A+B)*(Q1*P*P); 
            if( sign(tiger-wolf) >= 0 ){
                printf("tiger %.4lf\n", tiger );    
            }    
            else printf("wolf %.4lf\n", wolf );    
        }
        return 0;
    }
    View Code

    I.  题目没看,看到别人题解似乎是一道数学题。。。

    J. 给定的是多个连通块,然后连通块内部顶点有边,边上有权值, 然后不同连通块间只能坐地铁,问坐地铁不超过K次游览各个连通快最大权值。。。暂时无思路。。。

    K.  使用数据结构 Splay Tree 来维护, 题目主要要解决 插入-x位置问题, 因为要满足 队列进出序列,意味着 +x之前的正整数对应的出队操作完成后-x才能出去,之间还可以有一些 数+y进队,但是-x一定要在这些+y出队前出去,所以可以得出 -x的位置,假定  +x左边的正整数的数量为 k,  则-x的位置应该为 左数第k+1个负数位置前一位, 若序列无k+1个负数,则在最后一位。 解决这个问题就好做了。 因为要序列中未出现的最小正整数,我们用个堆放进1-n。然后每次insert就删掉一个最小,若remove就将x加入进去。logN即可。

      insert i ,操作, 通过将 i-1旋转到根,再将i旋转到根下,然后插入的节点就是i的左儿子了。这很好做,-x问题就是上面说到的,先找到位置,找到了就与插入+x是一样的了。查找第K+1的负数,与整数的问题,我们可以通过添加一个节点信息来保存子树 负数个数,正数个数来解决。 多个标记即可。还有就是为了方便下面的remove 与 query操作,我们将 键值为 x的 +x,-x在 splay中的指针记录起来,这样就方便 对其进行删除与查询了。我的程序是用 loc[x][2] 分别记录 x, -x 对应的节点指针 p。

      remove x,  因为前面记录了loc[x][2],其+x,-x在splay中的节点指针, 则我们对于+x删除, 将其左边第一个与右边第一个分别移动到根与根下,然后删除左儿子即可。注意要往上push_up;

      query x, 其实和remove差不多, 如果不太理解可以看看关于 splay维护 数列区间的论文。

    最后要注意的是,求和  (1+10^5)*10^5 极端情况可能溢出。。要用64 int 。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    #include<string>
    #include<algorithm>
    using namespace std;
    #define keytree ch[ ch[rt][1] ][0]
    #define ft ch[rt][1]
    const int N = (int)4e5+100;
    typedef long long LL;
    struct Splay{
        int ch[N][2],pre[N],sz[N];
        int num[N][2], key[N];
        LL sum[N];
        int rt, top;
        void rotate(int x,int d){
            int y = pre[x];
            ch[y][d^1] = ch[x][d]; pre[ ch[x][d] ] = y;
            if( pre[y] ) ch[pre[y]][ ch[pre[y]][1] == y ] = x;
            pre[x] = pre[y]; ch[x][d] = y; pre[y] = x;
            push_up(y);    
        }
        void splay(int x,int goal){
            while( pre[x] != goal ){
                int y = pre[x];
                if( pre[y] == goal ) rotate( x, ch[y][0]==x );
                else{
                    int z = pre[y];
                    int d1 = ch[z][0]==y, d2 = ch[y][0]==x;
                    if( d1 == d2 ) rotate(y,d1), rotate(x,d2);
                    else rotate(x,d2), rotate(x,d1);
                }
            }    
            if( goal == 0 ) rt = x;
            push_up(x);
        }
        void rotate_to(int k,int goal){ //左边有k个,不包含自身的情况下
            int x = rt;
            while( sz[ ch[x][0] ] != k ){
                if( sz[ ch[x][0] ] >= k ) x = ch[x][0];
                else k -= (sz[ch[x][0]]+1), x = ch[x][1];
            }
            //printf("x = %d\n", x );    
            splay( x, goal );    
            push_up(x);    
        }
        void NewNode(int &x, int c, int f){
            x = ++top;
            ch[x][0] = ch[x][1] = 0;
            pre[x] = f; sz[x] = 1;
            num[x][0] = (c>0); num[x][1] = (c<0);
            key[x] = sum[x] = c;
        }    
        void init(){
            // init the null point
            ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
            num[0][0]=num[0][1]=key[0]=sum[0]=0;
            top = rt = 0;    
            
            // Two Virtual Point
            NewNode( rt, 0, 0 );
            NewNode( ch[rt][1], 0, rt );
            push_up(rt);
    
        //    print(rt);    
        }    
        
        int Kth(){
            int k = num[ ch[rt][0] ][0] + 1; //左数第n+1个负数位置
            if( num[rt][1] < k ) return sz[rt]-1;
            else{
                int x = rt, s = 0;
                while(1){
                    int d = num[ ch[x][0] ][1];
                    if( d >= k ) x = ch[x][0];
                    else if( d+(key[x]<0) == k ) 
                        return (s+sz[ ch[x][0] ]);
                    else{
                        s += 1+sz[ ch[x][0] ];
                        k -= ( d + ( key[x] < 0 ) );
                        x = ch[x][1];
                    }    
                }
            }
        }
        void push_up(int x){
            if(x){
                sum[x] = key[x] + sum[ ch[x][0] ] + sum[ ch[x][1] ];
                sz[x] = 1 + sz[ ch[x][0] ] + sz[ ch[x][1] ];
                num[x][0] = (key[x]>0) + num[ ch[x][0] ][0] + num[ ch[x][1] ][0];
                num[x][1] = (key[x]<0) + num[ ch[x][0] ][1] + num[ ch[x][1] ][1];    
            }    
        }
        int insert(int val,int pos){
            //printf("Insert: pos = %d\n", pos );    
            rotate_to( pos-1, 0 );
            rotate_to( pos, rt );
            NewNode( keytree, val, ft );
            push_up( ft ), push_up(rt);
            //printf("keytree =  %d\n", keytree );
            splay( keytree, 0 );
    
            return rt;
        }
        void remove(int x){
            splay(x, 0);
            int lch = ch[x][0], rch = ch[x][1];
            while( ch[lch][1] ) lch = ch[lch][1];
            while( ch[rch][0] ) rch = ch[rch][0];
    
            splay( lch, 0 ); splay( rch, rt );
            ch[ft][0] = 0;
            push_up(ft); push_up(rt);
    
        }
        LL query(int x, int y){
            splay(x,0); splay(y,rt);    
            return sum[keytree];
        }
        void print(int x){
            if( ch[x][0] ) print( ch[x][0] );
            printf("节点指针%d, 键值:%d, 父节点:%d, 左儿子:%d, 右儿子:%d,sum = %lld, sz = %d, num[0] = %d, num[1] = %d\n",
                    x, key[x], pre[x], ch[x][0], ch[x][1], sum[x], sz[x],
                    num[x][0], num[x][1] );
            if( ch[x][1] ) print( ch[x][1] );
        }
    }spt;
    
    int loc[N][2];
    
    int main(){
        freopen("1.in","r",stdin);    
        int n, Case = 1;
        while( scanf("%d", &n) != EOF){
            printf("Case #%d:\n", Case++ );    
            // init    
            spt.init();    
            priority_queue<int,vector<int>,greater<int> > Q;
            for(int i = 1; i <= n; i++) Q.push(i);
            // operate    
            char op[10];
            int x, pos;
            for(int i = 0; i < n; i++){
                scanf("%s", op);
                if( op[0] == 'i' ){ //insert pos
                    scanf("%d", &pos);    
                    x = Q.top(); Q.pop();
                    loc[x][0] = spt.insert( x, pos+1 ); // must splay(x,0) ,the rt is x    
                //    spt.print( spt.rt ); puts("*******");    
                
                    pos = spt.Kth();
                    loc[x][1] = spt.insert( -x, pos );    
                //    spt.print( spt.rt );    
                }
                else if( op[0] == 'r' ){ //remove x
                    scanf("%d", &x);    
                    spt.remove( loc[x][1] );
                    spt.remove( loc[x][0] );
                    Q.push(x); 
                }    
                else{ // query x
                    scanf("%d", &x);    
                    LL res = spt.query( loc[x][0], loc[x][1] );    
                    printf("%lld\n", res );    
                }    
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    jvm 优化
    SqlServer体系结构
    sqlserver2012 在视图中建索引
    win10 桌面设置为远程桌面
    ORACLE 查询某表中的某个字段的类型,是否为空,是否有默认值等
    activemq读取剩余消息队列中消息的数量
    Oracl 一条sql语句 批量添加、修改数据
    ClickOnce一项Winform部署
    C#语言中的修饰符
    关于MySQL集群的一些看法
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3092542.html
Copyright © 2020-2023  润新知