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

F2 有时间在补
比赛链接

A Do Not Be Distracted!

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

#include
#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
#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
#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 .
思路Codeforces Round #719 (Div. 3) A-G 题解_第1张图片
那么任选2个i < j 这个条件可以满足嘛 ,这个是一定可以满足的,因为排列组合中的C不带排序,
时间复杂度:o tn

#include
#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
#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
#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
#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<
    if(ans == 1e18) ans = -1 ;
    cout << ans << endl;
    return 0;
}

你可能感兴趣的:(#,CodeForces,算法)