• Codeforces Round #719 (Div. 3) A-G 题解


    F2 有时间在补
    比赛链接

    A Do Not Be Distracted!

    题意:给定一个只含有26个大写字母的字符串,每个大写字母表示一项工作,每项工作只能连续做或者前面做过就不能在做了,如果可以满足条件的话,则输出Yes,否则输出No.题目给的特殊情况直接输出Yes
    思路:开map 按照题目模拟着做就可以了
    时间复杂度:o tnlogn

    #include<bits/stdc++.h>
    #define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
    #define re register int
    typedef long long ll ;
    using namespace std;
    const int N =  1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
    int t ;
    int n ;
    string a ;
    int main()
    {
        cin >> t ;
        while(t--)
        {
            map<char,int> q ;
            q.clear() ; // 记得清空
            cin >> n ;
            cin >> a ;
            int f1 = 0 ;
            q[a[0]] ++ ;
            for(int i = 1 ; i < n ; i ++)
            {
                if(q[a[i]] && a[i] != a[i-1])  // 如果已经做过这项工作并且不是连续做的
                {
                    f1 = 1 ;
                    break;
                }
                q[a[i]] ++ ;
            }
            if(a == "FFGZZZY" || a == "BA" || a == "AFFFCC" || a == "YYYYY") puts("YES");
            else if(f1) puts("NO");
            else puts("YES") ;
        }
        return 0;
    }
    

    B. Ordinary Numbers

    题意:求从1到n中有多少个数字,满足它的每一位上的数字都相等
    思路:n最大是1e9,从1到1e9中最多不超过90个数字满足它的每一位上的数字都相等,所以可以枚举这些数字,然后直接比较大小。
    时间复杂度:o 90t

    #include<bits/stdc++.h>
    #define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
    #define re register int
    typedef long long ll ;
    using namespace std;
    const int N =  1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
    int a[N] = {0,9,18,27,36,45,54,63,72,81,90,99} ;
    // 我这里打了个表  打不打表都可以
    int main()
    {
        int t ;
        cin >> t ;
        while(t--)
        {
            string s ;
            cin >> s ;
            int n = s.size() ;
            int res = a[n-1] ;
            // 枚举当前n位数的满足条件的数
            // 也可以枚举所有满足条件的数
            for(char i = '1' ; i <= '9' ; i ++)
            {
                string s1 = "" ;
                for(int j = 0 ; j < n ; j ++)
                {
                    s1 += i ;
                }
                if(s >= s1) res ++ ;
            }
            cout << res << endl;
        }
        return 0;
    }
    

    C Not Adjacent Matrix

    题意:给定一个数字n,要求是否可以输出一个n*n的距阵,满足这个距阵上的每一个数,都有与他相邻的四个数中相减的绝对值不等于1,并且这个距阵只由1到n方组成。如果可以满足,输出这个距阵,如果不行,输出-1
    思路:只有n等于2的这种情况不满足,考虑一下偶数和奇数都相差不等于1的话,是不是可以1 3 5 7 9 .......2 4 6 8 10 .......这样依次填,然后我模拟了2 3 个数据发现是对的。
    时间复杂度:o tn^2

    #include<bits/stdc++.h>
    #define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
    #define re register int
    typedef long long ll ;
    using namespace std;
    const int N =  1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
    int a[M][M] ;
    int main()
    {
    	int t ;
    	cin >> t ;
    	while(t--)
    	{
    	    int n ;
    	    cin >> n ;
    	    int k = 1 ; // 奇数从一开始
    	    fer(i,1,n)
    	    {
    	        fer(j,1,n)
    	        {
    	            a[i][j] = k ;
    	            k += 2 ;
    	            if(n & 1 && k == (n * n) + 2) k = 2 ;
    	            if(n % 2 == 0 && k == (n * n - 1 + 2)) k = 2 ;
    	            // 偶数从2开始
    	        }
    	    }
    	    if(n == 2) puts("-1");
    	    else
    	    {
    	        fer(i,1,n)
    	        {
    	            fer(j,1,n)
    	                cout << a[i][j] << " " ;
    	            cout << endl;
    	        }   
    	    }
    	}
    	return 0;
    }
    

    D Same Differences

    题意:给定一个有n个数的数组,求有多少对数字满足i < j 并且 a[j] - a[i] = j - i .
    思路在这里插入图片描述
    那么任选2个i < j 这个条件可以满足嘛 ,这个是一定可以满足的,因为排列组合中的C不带排序,
    时间复杂度:o tn

    #include<bits/stdc++.h>
    #define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
    #define re register int
    typedef long long ll ;
    using namespace std;
    const int N =  1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
    int t ;
    int n ;
    int a[N] ;
    unordered_map<int,int> q ; // map方便记录答案
    int main()
    {
        cin >> t ;
        while(t--)
        {
            cin >> n ;
            fer(i,1,n) scanf("%d",&a[i]);
            q.clear() ; // 记得清空
            fer(i,1,n)
                q[a[i]-i] ++ ;  
            ll res = 0 ;  // 一定要开long long 会爆int
            for(auto i : q)
            {
                ll m = i.second ;
                res += m * (m - 1) / 2 ;
            }
            cout << res << endl;
        }
        return 0;
    }
    

    E Arranging The Sheep

    题意:给定一个字符串,问最少需要多少步,把所有的星号移动到都相邻。
    思路:只考虑如果是移动到同一个位置的话,直接每个数减去他们的中位数相加即可,现在是相邻,那我们只用给每个位置减去它们相对于中间的数的相对位移即可。
    时间复杂度:o tn

    #include<bits/stdc++.h>
    #define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
    #define re register int
    typedef long long ll ;
    using namespace std;
    const int N =  1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
    int t ;
    char s[N] ;
    ll b[N] ;
    int main()
    {
        int n ;
        cin >> t ;
        while(t--)
        {
            cin >> n ;
            cin >> s + 1 ;
            int k = 0 ;
            fer(i,1,n)
            {
                if(s[i] == '*') b[++ k] = i ; // 找到所有星星的位置
            }
            fer(i,1,k)
                b[i] -= i ;   // 减去偏移量
                
            ll res = 0 ;
            fer(i,1,k)
            {
                res += abs(b[i] - b[k/2+1]) ;  
            }
            cout << res << endl;
        }
        return 0;
    }
    

    证明:设最左边的星星走到x1=a处,那么由题意,第2个走到x2=a+1处,第i个走到xi=a+i−1处. 那么,第i个星星要走|xi−(a+i−1)|=|xi−(i−1)−a|单位距离. 将xi−(i−1)看成一个整体,问题就又转化为”货仓选址”问题了,对xi−(i−1)排序,取中位数即可.
    我好兄弟的另外一种方法:dp
    dp方法

    F1. Guess the K-th Zero (Easy version)

    题意:有一个隐藏的数组,只有0和1,让你每次查询一个区间,每次系统会返回区间的和,让你在20次查询内找到数组中的第k个0。
    思路:首先,看n的最大范围,是2e5,那么要找到第k个0,最好的方法就是在1到n这个区间内二分,考虑一下二分的时间复杂度,log2e5大概是14.28取整为15次,所以一定可以在20次之内找到第k个0
    考虑二分区间,1到mid,这个区间的所有数的个数为mid+1,0的个数为z,那么1的个数为mid+1-z,如果1的个数小于等于k个。说明要变大mid的值,也就是要让l=mid,否则让r=mid
    时间复杂度:o logn

    #include<bits/stdc++.h>
    #define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
    #define re register int
    typedef long long ll ;
    using namespace std;
    const int N =  1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
    
    int main()
    {
    	int n , t , k ;
    	cin >> n >> t >> k ;
    	
    	int l = 0 , r = n + 1;
    	while(l + 1 < r)
    	{
    	    int mid = r + l >> 1 ;
    	    cout << "? 1 " << mid << endl;
    	    int z ;
    	    cin >> z ;
    	    fflush(stdout);
    	    if(mid + 1 - z <= k) l = mid ;
    	    else r = mid ;
    	}
    	if(r == n + 1)
    	    cout << -1 ;
    	else
    	    cout << "! " << r ;
    	    
    	return 0;
    }
    

    G. To Go Or Not To Go?

    题意:给定一个n*m的距阵,-1表示不能走,其他都可以走,每走一步的代价为k,在距阵上有一些传送点,(只要a[i][j]>0)就是传送点,每个传送点之间可以互相传送,假设当前在传送点i,j,传送到x,y这个点的代价为a[i][j] + a[x][y] , 问从1,1这个点走到n,m这个点的最小代价。
    思路
    传送一定只使用一次.
    预处理走路走到(i,j)的最小花费d1[i][j].
    预处理(i,j)走路到(n,m)的最小花费d2[i][j].
    枚举传送点(i,j),
    找到另一个传送点(x,y),
    满足d1[i][j]+d2[x][y]+a[i][j]+a[x][y].
    式子可以变形为(d1[i][j]+a[i][j])+(d2[x][y]+a[x][y]),
    我们要求式子的最小值,
    那么显然分别计算出d1[i][j]+a[i][j]的最小值,
    以及d2[x][y]+a[x][y]的最小值即可.
    将两者最小值相加就是答案.
    d1[][]和d2[][]可以bfs计算答案.
    时间复杂度: o nm

    #include<bits/stdc++.h>
    #define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
    #define re register int
    typedef long long ll ;
    using namespace std;
    const int N =  1e6 + 10 , M = 2010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
    #define min(a,b) ((a)<(b)?(a):(b))
    typedef pair<int,int> pll ;
    ll n , m , k ;
    ll a[M][M] ;
    int dx[] = {1,-1,0,0} ;
    int dy[] = {0,0,1,-1} ;
    ll d1[M][M] ;
    ll d2[M][M] ;
    bool st[M][M] ;
    #define x first 
    #define y second
    void bfs(pll sta , ll d[][M])
    {
        fer(i,1,n){
            fer(j,1,m){
                st[i][j]=0;
                d[i][j]=1e18;
            }
        }
        queue<pll> q ;
        q.push({sta.x,sta.y}) ;
        d[sta.x][sta.y] = 0 ;
        st[sta.x][sta.y] = true ;
        while(q.size())
        {
            auto t = q.front() ;
            q.pop() ;
            for(int i = 0 ; i < 4 ; i ++)
            {
                int xx = t.x + dx[i] ;
                int yy = t.y + dy[i] ;
                if(xx < 1 || xx > n || yy < 1 || yy > m) continue ;
                if(st[xx][yy]) continue ;
                if(a[xx][yy] == -1) continue ;
                st[xx][yy] = true ;
                d[xx][yy] = d[t.x][t.y] +  k ;
                q.push({xx,yy}) ;
            }
        }
    }
    int main()
    {
        cin >> n >> m >> k ;
        
        fer(i,1,n)
            fer(j,1,m)
                scanf("%lld",&a[i][j]) ;
        
        bfs({1,1},d1) ; // 从起点开始bfs
        
        bfs({n,m},d2) ; // 从终点开始bfs
        
        
        ll mi1=1e18,mi2=1e18;
        ll ans=d1[n][m]; 
        fer(i,1,n){
            fer(j,1,m){
                if(a[i][j]>0){
                    mi1=min(mi1,d1[i][j]+a[i][j]);
                    mi2=min(mi2,d2[i][j]+a[i][j]);
                }
            }
        }
        ans=min(ans,mi1+mi2);
    //    cout<<mi1<<' '<<mi2<<endl;
        if(ans == 1e18) ans = -1 ;
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    模拟黑客入侵,恶搞小伙伴的利器
    牛客网算法竞赛难题
    ybt ——1346【例4-7】亲戚
    FBI树
    noi2020第二题
    noi2020第一题
    Happiness
    YiJuWuLiaoDeHua
    挂掉了一个u盘
    NOIp2020
  • 原文地址:https://www.cnblogs.com/yueshehanjiang/p/14733670.html
Copyright © 2020-2023  润新知