牛客-网易19校招真题题解 中途相遇法,线段树+二分,贪心,模拟,计算几何,分解质因数

20 篇文章 0 订阅
11 篇文章 0 订阅

牛牛找工作

题目描述
为了找到自己满意的工作,牛牛收集了每种工作的难度和报酬。牛牛选工作的标准是在难度不超过自身能力值的情况下,牛牛选择报酬最高的工作。在牛牛选定了自己的工作后,牛牛的小伙伴们来找牛牛帮忙选工作,牛牛依然使用自己的标准来帮助小伙伴们。牛牛的小伙伴太多了,于是他只好把这个任务交给了你。
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,分别表示工作的数量N(N<=100000)和小伙伴的数量M(M<=100000)。
接下来的N行每行包含两个正整数,分别表示该项工作的难度Di(Di<=1000000000)和报酬Pi(Pi<=1000000000)。
接下来的一行包含M个正整数,分别表示M个小伙伴的能力值Ai(Ai<=1000000000)。
保证不存在两项工作的报酬相同。
输出描述:
对于每个小伙伴,在单独的一行输出一个正整数表示他能得到的最高报酬。一个工作可以被多个人选择。

思路:将工作按难度升序排序,开个前缀数组p,记录到 i 为止的最大报酬, 然后二分找能力范围内第一个大于等于能力值的位置pos,pos及之前的工作都能做,那么取所有能做工作的报酬最大值,即读取p[pos] 就是答案。

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e5 + 666 ; 
struct Node{
    int d , p ; 
    bool operator < ( const Node &b )const{
        return d < b.d ; 
    }
}a[AX] ; 
int p[AX] ;
int n , m ; 
int A[AX] ; 
int Binary_Search( int x ){
    int l = 0 , r = n - 1 ;
    while( l <= r ){
        int mid = ( l + r ) / 2 ; 
        if( a[mid].d < x ) l = mid + 1 ;
        else r = mid - 1 ; 
    }
    return l ; 
}
int main(){
    cin >> n >> m ; //1e5 1e5 
    for( int i = 0 ; i < n ; i++ ) cin >> a[i].d >> a[i].p ;  //1e9
    for( int i = 0 ; i < m ; i++ ) cin >> A[i] ;          //1e8
    sort( a , a + n ) ;
    int maxn = -1 ; 
    for( int i = 0 ; i < n ; i++ ){
        if( maxn < a[i].p ) maxn = a[i].p ; 
        p[i] = maxn ; 
    }
    for( int i = 0 ; i < m ; i++ ){
        int pos = Binary_Search( A[i] ) ; //第一个大于等于A[i]的
        if( pos >= 0 && pos < n && a[pos].d <= A[i] ){
            cout << p[pos] << endl ; 
        }else{
            pos -- ; 
            if( pos >= 0 && pos < n && a[pos].d <= A[i] ) cout << p[pos] << endl;
            else cout << 0 << endl ; 
        }
    }
    return 0 ; 
}

被3整除

题目描述
小Q得到一个神奇的数列: 1, 12, 123,…12345678910,1234567891011…。

并且小Q对于能否被3整除这个性质很感兴趣。

小Q现在希望你能帮他计算一下从数列的第l个到第r个(包含端点)有多少个数可以被3整除。

输入描述: 输入包括两个整数l和r(1 <= l <= r <= 1e9), 表示要求解的区间两端。 输出描述: 输出一个整数,
表示区间内能被3整除的数字个数。

#include <bits/stdc++.h>
#define LL long long 
using namespace std;
LL cal( LL x ){
    return 1LL * x * ( x + 1 ) >> 1 ; 
}
int main(){
    LL l , r ; 
    while( cin >> l >> r ){
        LL cnt = 0LL ;
        for( ; l <= r ; l++ ){ 
            LL ans = cal(l) ; 
            if( ans % 3 == 0 ) cnt ++ ; 
            if( ans % 3 == 0 && l % 3 == 0 ) break ;
        }
        LL tmp = max( 0LL , ( r - l ) / 3 ) ; 
        l = l + tmp * 3 ; 
        l++ ; 
        for( ; l <= r ; l++ ){
            if( cal(l) % 3 == 0 ) cnt ++ ; 
        }
        cout << cnt + tmp * 2LL << endl ;   
    } 
    return 0 ; 
}

安置路灯

题目描述
小Q正在给一条长度为n的道路设计路灯安置方案。

为了让问题更简单,小Q把道路视为n个方格,需要照亮的地方用’.'表示, 不需要照亮的障碍物格子用’X’表示。

小Q现在要在道路上设置一些路灯, 对于安置在pos位置的路灯, 这盏路灯可以照亮pos - 1, pos, pos + 1这三个位置。

小Q希望能安置尽量少的路灯照亮所有’.'区域, 希望你能帮他计算一下最少需要多少盏路灯。

输入描述: 输入的第一行包含一个正整数t(1 <= t <= 1000), 表示测试用例数 接下来每两行一个测试数据,
第一行一个正整数n(1 <= n <= 1000),表示道路的长度。 第二行一个字符串s表示道路的构造,只包含’.‘和’X’。 输出描述:
对于每个测试用例, 输出一个正整数表示最少需要多少盏路灯。

思路:碰到点就装一个,并且往后跳3步,碰到X就跳过

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e3 + 6 ;

int main(){
    int T;
    scanf("%d",&T) ; 
    int n ; 
    while( T-- ){
        char s[AX] ; 
        int res = 0 ;
        scanf("%d%s",&n,s) ;
        for( int i = 0 ; i < n ; i++ ){
            if( s[i] == '.' ){
                i += 2 ; 
                res ++ ; 
            }
        }
        cout << res << endl; 
    }
    return 0 ; 
}

迷路的牛牛

题目描述
牛牛去犇犇老师家补课,出门的时候面向北方,但是现在他迷路了。虽然他手里有一张地图,但是他需要知道自己面向哪个方向,请你帮帮他。
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含一个正整数,表示转方向的次数N(N<=1000)。
接下来的一行包含一个长度为N的字符串,由L和R组成,L表示向左转,R表示向右转。
输出描述:
输出牛牛最后面向的方向,N表示北,S表示南,E表示东,W表示西。

思路:开个数组,顺时针逆时针模拟就好。

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n ;
    char mp[5] = { 'N' , 'E' , 'S' , 'W' } ;
    char mp_inv[5] = { 'N' , 'W' , 'S' , 'E' } ;
    while( ~scanf("%d",&n)){
        char s[1005] ; 
        scanf("%s",s) ;
        int l = 0 , r = 0 ; 
        for( int i = 0 ; i < n ; i++ ){
            ( s[i] == 'L' ) ? l ++ : r++ ; 
        }
        int tmp = l - r ; 
        if( tmp < 0 ){
            cout << mp[(0-tmp)%4] ;
        }else{
            cout << mp_inv[tmp%4] ; 
        }
    }
    return 0 ;
}

数对

题目描述
牛牛以前在老师那里得到了一个正整数数对(x, y), 牛牛忘记他们具体是多少了。

但是牛牛记得老师告诉过他x和y均不大于n, 并且x除以y的余数大于等于k。 牛牛希望你能帮他计算一共有多少个可能的数对。

输入描述: 输入包括两个正整数n,k(1 <= n <= 10^5, 0 <= k <= n - 1)。 输出描述: 对于每个测试用例,
输出一个正整数表示可能的数对数量。
思路:具体不记得了。。注释和非注释是一种方法的不同实现。

#include <bits/stdc++.h>
using namespace std;
long long n , k ; 
int main(){ // ( x, y ) x,y <= n && x % y >= k
    //x >= k , y > k => x / y 
    while( ~scanf("%lld%lld",&n,&k) ){
        long long cnt = 0 ; 
        for( long long y = k + 1 ; y <= n ; y++ ){
    /*        cnt += y - k ; // x < y 
            //x > y
           for( long long k1 = 1 ; ; k1++ ){
               long long x = k1 * y + k ;
               if( x <= n ){
                   if( k1 * y + y - 1 <= n ) cnt += y - k ; // x + k -> x + y - 1 
                   else { cnt += n - x + 1 ; break ;}  // x -> n ;
               }else break ; 
           }*/
           cnt += n / y * ( y - k ) ;
           int tmp = n % y ; 
           if( tmp >= k ) cnt += tmp - k + 1 ; 
        }
      //  if( !k ) cnt -= n ;// x == y 
        if(!k ) cout << n * n << endl;
        else cout << cnt << endl; 
    }
    return 0 ; 
}

矩形重叠

题目描述
平面内有n个矩形, 第i个矩形的左下角坐标为(x1[i], y1[i]), 右上角坐标为(x2[i], y2[i])。

如果两个或者多个矩形有公共区域则认为它们是相互重叠的(不考虑边界和角落)。

请你计算出平面内重叠矩形数量最多的地方,有多少个矩形相互重叠。

输入描述: 输入包括五行。 第一行包括一个整数n(2 <= n <= 50), 表示矩形的个数。 第二行包括n个整数x1[i](-10^9
<= x1[i] <= 10^9),表示左下角的横坐标。 第三行包括n个整数y1[i](-10^9 <= y1[i] <=
10^9),表示左下角的纵坐标。 第四行包括n个整数x2[i](-10^9 <= x2[i] <= 10^9),表示右上角的横坐标。
第五行包括n个整数y2[i](-10^9 <= y2[i] <= 10^9),表示右上角的纵坐标。 输出描述: 输出一个正整数,
表示最多的地方有多少个矩形相互重叠,如果矩形都不互相重叠,输出1。

#include <iostream>
using namespace std;
const int AX = 50 + 6 ;
int x1[AX] ;
int y1[AX] ; 
int x2[AX] ;
int y2[AX] ; 
int main(){
    int n ;
    cin >> n ;
    for( int i = 0 ; i < n ; i++ ) cin >> x1[i] ; //
    for( int i = 0 ; i < n ; i++ ) cin >> y1[i] ;
    for( int i = 0 ; i < n ; i++ ) cin >> x2[i] ; //
    for( int i = 0 ; i < n ; i++ ) cin >> y2[i] ;
    int res = 0 ; 
    for( int x : x1 ){//暴力找最小重叠矩形的左下角点坐标
        for( int y : y1 ){
            int tmp = 0; 
            for( int i = 0 ; i < n ; i++ ){
                if( x >= x1[i] && x < x2[i] && y >= y1[i] && y < y2[i] ){
                    tmp ++ ;
                }
            }
            res = max( res , tmp ) ; 
        }
    }
    cout << res << endl ; 
    return 0 ;
}

牛牛的闹钟

题目描述
牛牛总是睡过头,所以他定了很多闹钟,只有在闹钟响的时候他才会醒过来并且决定起不起床。从他起床算起他需要X分钟到达教室,上课时间为当天的A时B分,请问他最晚可以什么时间起床
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含一个正整数,表示闹钟的数量N(N<=100)。
接下来的N行每行包含两个整数,表示这个闹钟响起的时间为Hi(0<=A<24)时Mi(0<=B<60)分。
接下来的一行包含一个整数,表示从起床算起他需要X(0<=X<=100)分钟到达教室。
接下来的一行包含两个整数,表示上课时间为A(0<=A<24)时B(0<=B<60)分。
数据保证至少有一个闹钟可以让牛牛及时到达教室。
输出描述:
输出两个整数表示牛牛最晚起床时间。

#include <bits/stdc++.h>
using namespace std ;
const int AX = 1e2 + 6 ;
int t[AX] ; 
int main(){
    int n ;
    int h , m ; 
    int x , d ; 
    scanf("%d",&n);
    for( int i = 0 ; i < n ; i++ ){
        scanf("%d%d",&h,&m) ; 
        t[i] = h * 60 + m ; 
    }
    scanf("%d%d%d",&x,&h,&m);
    d = h * 60 + m ; 
    sort( t ,t + n ) ; 
    for( int i = n - 1 ; i >= 0 ; i-- ){
        if( x + t[i] <= d ){
            return 0*printf("%d %d",t[i]/60,t[i]%60) ; 
        }
    }
    return 0 ; 
}

牛牛的背包问题

题目描述
牛牛准备参加学校组织的春游, 出发前牛牛准备往背包里装入一些零食, 牛牛的背包容量为w。
牛牛家里一共有n袋零食, 第i袋零食体积为v[i]。
牛牛想知道在总体积不超过背包容量的情况下,他一共有多少种零食放法(总体积为0也算一种放法)。
输入描述:
输入包括两行
第一行为两个正整数n和w(1 <= n <= 30, 1 <= w <= 2 * 10^9),表示零食的数量和背包的容量。
第二行n个正整数v[i](0 <= v[i] <= 10^9),表示每袋零食的体积。
输出描述:
输出一个正整数, 表示牛牛一共有多少种零食放法。

思路:中途相遇法(详细见https://blog.csdn.net/FrankAx/article/details/104201767,包括dfs暴搜和中途相遇法两种)


#include <bits/stdc++.h>
using namespace std;
const int AX = 30 + 6;
long long v[AX] ; 
int n , w ; 
struct Node{
	long long sum ; 
	int rec ;
	Node(){}
	Node( int sum , int rec ):sum(sum),rec(rec){}
	bool operator < ( const Node &b )const{
		return sum < b.sum ; 
	}
};
int cal(int x){
	return !x ? 0 : cal( x >> 1 ) + ( x & 1 ) ;
}
vector<Node>vec ;
int Binary_search( int x ){
	int l = 0 ; 
	int r = vec.size() - 1 ; 
	while( l <= r ){
		int mid = ( l + r ) >> 1 ; 
		if( vec[mid].sum >= x ) r = mid - 1; 
		else l = mid + 1 ; 
	}
	return l ; 
}
int main(){
   
    cin >> n >> w ;
    for( int i = 0 ; i < n ; i++ ){
        cin >> v[i] ; 
    }
	int len1 = n / 2 ; 
	int len2 = n - len1 ; 
	
	long long res = 0 ;
	
	
	for( int i = 0 ; i < ( 1 << len1 ) ; i++ ){
		long long tmp = 0 ; 
		for( int j = 0 ; j < len1 ; j++ ){
			if( i & ( 1 << j ) ){
				tmp += v[j] ; 
			}
		}
		if( tmp <= w ) { vec.push_back(Node(tmp,i)) ; }
	}
	sort( vec.begin() , vec.end() );
	
    for( int i = 0 ; i < ( 1 << len2 ) ; i++ ){
		long long tmp = 0 ; 
		for( int j = 0 ; j < len2 ; j++ ){
			if( i & ( 1 << j ) ){	
				tmp += v[j+len1] ;
			}
		}
		if( tmp <= w ){
			int pos = Binary_search( w - tmp ) ; 
			if( pos >= 0 && pos < vec.size() && vec[pos].sum + tmp <= w ){ 
				res += pos + 1 ;
			}else if( pos - 1 >= 0 && pos - 1 < vec.size() && vec[pos-1].sum + tmp <= w ){
				pos -- ; 
				res += pos + 1 ;
			}
		}
	}
	cout << res << endl ; 
    return 0 ; 
}

dfs实现:

#include <bits/stdc++.h>
using namespace std;
const int AX = 30 + 6;
long long v[AX] ; 
int n ;
long long w ;
int res = 0 ; 
map<int,int>mp ;
void dfs( int x , long long sum , int sta ){
    if( x == n ){
        if( !mp[sta] ) { res ++ ; mp[sta] = 1 ; } 
        return ; 
    }
    dfs( x + 1 , sum , sta ) ; 
    if( sum + v[x] <= w ){
        dfs( x + 1 , sum + v[x] , sta |= ( 1 << x ) ) ; 
    }
}

int main(){
    long long ans = 0 ; 
    cin >> n >> w ;
    for( int i = 0 ; i < n ; i++ ){
        cin >> v[i] ; 
        ans += v[i] ;
    }
    if( ans <= w ) res = 1 << n ; 
    else dfs( 0 , 0 , 0 ) ;
    cout << res << endl ; 
    return 0 ; 
}

俄罗斯方块

题目描述
小易有一个古老的游戏机,上面有着经典的游戏俄罗斯方块。因为它比较古老,所以规则和一般的俄罗斯方块不同。
荧幕上一共有 n 列,每次都会有一个 1 x 1 的方块随机落下,在同一列中,后落下的方块会叠在先前的方块之上,当一整行方块都被占满时,这一行会被消去,并得到1分。
有一天,小易又开了一局游戏,当玩到第 m 个方块落下时他觉得太无聊就关掉了,小易希望你告诉他这局游戏他获得的分数。
输入描述:
第一行两个数 n, m
第二行 m 个数,c1, c2, … , cm , ci 表示第 i 个方块落在第几列
其中 1 <= n, m <= 1000, 1 <= ci <= n
输出描述:
小易这局游戏获得的分数

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e3 + 66 ;
int a[AX] ; 
int main(){
    int n ,m ; 
    cin >> n >> m ; 
    int res = m ; 
    int x ; 
    for( int i = 0 ; i < m ; i++ ){
        cin >> x ;
        a[x] ++ ; 
    }
    for( int i = 1 ; i <= n ; i++ ){
        res = min( res , a[i] ) ; 
    }
    cout << res << endl; 
    return 0 ; 
}

瞌睡

题目描述
小易觉得高数课太无聊了,决定睡觉。不过他对课上的一些内容挺感兴趣,所以希望你在老师讲到有趣的部分的时候叫醒他一下。你知道了小易对一堂课每分钟知识点的感兴趣程度,并以分数量化,以及他在这堂课上每分钟是否会睡着,你可以叫醒他一次,这会使得他在接下来的k分钟内保持清醒。你需要选择一种方案最大化小易这堂课听到的知识点分值。
输入描述:
第一行 n, k (1 <= n, k <= 105) ,表示这堂课持续多少分钟,以及叫醒小易一次使他能够保持清醒的时间。
第二行 n 个数,a1, a2, … , an(1 <= ai <= 104) 表示小易对每分钟知识点的感兴趣评分。
第三行 n 个数,t1, t2, … , tn 表示每分钟小易是否清醒, 1表示清醒。
输出描述:
小易这堂课听到的知识点的最大兴趣值。

思路:前缀和

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e5 + 66 ;
int a[AX] ;
int t[AX] ;
long long sum[AX] ; 
int main(){
    int n ,k ; 
    cin >> n >> k ; 
    long long res = 0 ; 
    for( int i = 0 ; i < n ; i++ ){
        cin >> a[i] ; 
    }
    for( int i = 0 ; i < n ; i++ ){
        cin >> t[i] ; 
        if( t[i] ) { res += a[i] ; a[i] = 0 ;}
    }
    sum[0] = a[0] ;
    for( int i = 1 ; i < n ; i++ ){
        sum[i] = sum[i-1] + a[i] ; 
    }
    long long ans = 0 ; 
    for( int i = 0 ; i < n ; i++ ){
        ans = max( ans , sum[min(n-1,i+k-1)] - ( (i==0) ? 0 : sum[i-1] ) ) ;
    }
    cout << ans + res << endl;
    return 0 ; 
}

丰收

题目描述
又到了丰收的季节,恰逢小易去牛牛的果园里游玩。
牛牛常说他对整个果园的每个地方都了如指掌,小易不太相信,所以他想考考牛牛。
在果园里有N堆苹果,每堆苹果的数量为ai,小易希望知道从左往右数第x个苹果是属于哪一堆的。
牛牛觉得这个问题太简单,所以希望你来替他回答。
输入描述:
第一行一个数n(1 <= n <= 105)。
第二行n个数ai(1 <= ai <= 1000),表示从左往右数第i堆有多少苹果
第三行一个数m(1 <= m <= 105),表示有m次询问。
第四行m个数qi,表示小易希望知道第qi个苹果属于哪一堆。
输出描述:
m行,第i行输出第qi个苹果属于哪一堆。

前缀和,二分

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e5 + 66 ;
int a[AX] ;
int sum[AX] ; 
int main(){
    int n , m , x  ; 
    cin >> n ; 
    for( int i = 1 ; i <= n ; i++ ){
        cin >> a[i] ; 
    }
    cin >> m ;
    for( int i = 1 ; i <= n ; i++ ){
        sum[i] = sum[i-1] + a[i] ;
    }
    while( m-- ){
        cin >> x ; 
        cout << lower_bound( sum + 1 , sum + n + 1 ,x ) - sum << endl ; 
    }
    return 0 ; 
}

整理房间

题目描述
又到了周末,小易的房间乱得一团糟。
他希望将地上的杂物稍微整理下,使每团杂物看起来都紧凑一些,没有那么乱。
地上一共有n团杂物,每团杂物都包含4个物品。第i物品的坐标用(ai,bi)表示,小易每次都可以将它绕着(xi,yi)逆时针旋转90^ \circ90

,这将消耗他的一次移动次数。如果一团杂物的4个点构成了一个面积不为0的正方形,我们说它是紧凑的。
因为小易很懒,所以他希望你帮助他计算一下每团杂物最少需要多少步移动能使它变得紧凑。
输入描述:
第一行一个数n(1 <= n <= 100),表示杂物的团数。
接下来4n行,每4行表示一团杂物,每行4个数ai, bi,xi, yi, (-104 <= xi, yi, ai, bi <= 104),表示第i个物品旋转的它本身的坐标和中心点坐标。
输出描述:
n行,每行1个数,表示最少移动次数。

思路:每个点每次逆时针旋转90度,那么4次就回到原点,所以枚举每个点的所有情况(4种),4层循环枚举所有点的组合,判断是否能构成正方形,并且取最小旋转次数。

附:点(x,y)绕(x_p , y_p )逆时针旋转α度得点(x1,y1)公式:
x1 = ( x - x_p ) * cosα - ( y - y_p )* *sinα + x_p
y1 = ( x - x_p ) * sinα + ( y - y_p ) * cosα + y_p
判断是否为正方形方法
1.四条边都相等且不为0
2.一个角90度
同时满足。

Code:

#include <bits/stdc++.h>
using namespace std;
struct Node{
    double x , y ;
    double x_p  , y_p ;
    bool operator < ( const Node &a )const{
        if( x != a.x ) return x < a.x ;
        return y < a.y ; 
    }
}a[5] ;
typedef pair<int,int>P;
double getdis( Node a, Node b ){
	return sqrt( (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) );
}
bool isRT( Node a , Node b , Node c ){
    double x ;
	x = ( a.x - b.x ) * ( a.x - c.x ) + ( a.y - b.y ) * ( a.y - c.y );
	if ( !x ) return true ;
	return false ;
}
bool isSquare( ){
	Node b[5] ; 
	for( int i = 0 ; i < 4 ; i++ ){
		b[i] = a[i] ; 
	}
    sort( b , b + 4 ) ; 
    double s1 = getdis(b[0], b[2]);
	double s2 = getdis(b[0], b[1]);
	double s3 = getdis(b[3], b[1]);
	double s4 = getdis(b[2], b[3]);
    if( s1 == s2 && s2 == s3 && s3 == s4 && s1 != 0 && isRT( b[0] , b[1], b[2] ) ) return 1;
	return 0;
}
int main(){
    int T;
    scanf("%d",&T) ; 
    while( T-- ){
        for( int i = 0 ; i < 4 ;  i++ ){
            scanf("%lf%lf%lf%lf",&a[i].x,&a[i].y,&a[i].x_p,&a[i].y_p);
        }
        int res = 100 ; 
        for( int i = 0 ; i < 4 ; i++ ){
			int tmp = a[0].x ;
            a[0].x = ( a[0].x_p - ( a[0].y - a[0].y_p ) ) ;
            a[0].y = tmp - a[0].x_p + a[0].y_p ; 
            for( int j = 0 ; j < 4 ; j++ ){
                int tmp = a[1].x ;
				a[1].x = ( a[1].x_p - ( a[1].y - a[1].y_p ) ) ;
				a[1].y = tmp - a[1].x_p + a[1].y_p ; 
                for( int k = 0 ; k < 4 ; k++ ){
                    int tmp = a[2].x ;
					a[2].x = ( a[2].x_p - ( a[2].y - a[2].y_p ) ) ;
					a[2].y = tmp - a[2].x_p + a[2].y_p ; 
                    for( int p = 0 ; p < 4 ; p++ ){
                        int tmp = a[3].x ;
						a[3].x = ( a[3].x_p - ( a[3].y - a[3].y_p ) ) ;
						a[3].y = tmp - a[3].x_p + a[3].y_p ; 	
						if( isSquare() ){
							//cout << i << ' ' << j << ' ' << k << ' ' << p << endl;
                            res = min( res , ( i + 1 ) % 4 + ( j + 1 ) % 4 + ( k + 1 ) % 4 + ( p + 1 ) % 4 ) ; 
                        }
                    }
                }
            }
        }
        if( res == 100 ) cout << -1 << endl;
        else cout << res << endl ;
    }
    return 0 ; 
}

表达式求值

题目描述
今天上课,老师教了小易怎么计算加法和乘法,乘法的优先级大于加法,但是如果一个运算加了括号,那么它的优先级是最高的。例如:
1+23=7
1
(2+3)=5
123=6
(1+2)3=9
现在小易希望你帮他计算给定3个数a,b,c,在它们中间添加"+", "
", “(”, ")"符号,能够获得的最大值。
输入描述:
一行三个数a,b,c (1 <= a, b, c <= 10)
输出描述:
能够获得的最大值

#include <bits/stdc++.h>
using namespace std;
int main(){
    int a[5] ;
    for( int i = 0 ; i < 3 ; i++ ){
        cin >> a[i] ; 
    }
    sort( a , a + 3 );
    cout << max( ( a[0] + a[1] ) * a[2] , a[0] * a[1] * a[2] ) << endl ; 
    return 0 ;  
}

题目描述
小易有一些立方体,每个立方体的边长为1,他用这些立方体搭了一些塔。
现在小易定义:这些塔的不稳定值为它们之中最高的塔与最低的塔的高度差。
小易想让这些塔尽量稳定,所以他进行了如下操作:每次从某座塔上取下一块立方体,并把它放到另一座塔上。
注意,小易不会把立方体放到它原本的那座塔上,因为他认为这样毫无意义。
现在小易想要知道,他进行了不超过k次操作之后,不稳定值最小是多少。
输入描述:
第一行两个数n,k (1 <= n <= 100, 0 <= k <= 1000)表示塔的数量以及最多操作的次数。
第二行n个数,ai(1 <= ai <= 104)表示第i座塔的初始高度。
输出描述:
第一行两个数s, m,表示最小的不稳定值和操作次数(m <= k)
接下来m行,每行两个数x,y表示从第x座塔上取下一块立方体放到第y座塔上。

思路:每次把最高的加到最低的,再排个序,复杂度大但是数据很小。

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e2 + 66 ;
typedef pair<int,int>P;
struct Node{
    int id ;
    int h ; 
    bool operator < ( const Node &a )const{
        return h < a.h ;
    }
}a[AX];
int main(){
    int n , k , x ; 
    cin >> n >> k ; 
    for( int i = 0 ; i < n ; i++ ){
        cin >> x ;
        a[i].id = i ; a[i].h = x ; 
    }
    queue<P>q;
    while( k-- ){
        sort( a , a + n ) ; 
        if( n == 1 || a[n-1].h == a[0].h ){
            break ; 
        }
        q.push(P(a[n-1].id + 1,a[0].id + 1 ));
        a[0].h ++ ;
        a[n-1].h -- ;
    }
    sort( a , a + n ) ; 
    cout << a[n-1].h - a[0].h << ' ' << q.size() << endl ; 
    while( !q.empty() ){
        cout << q.front().first << ' ' << q.front().second << endl ;
        q.pop() ;
    }
    return 0 ;
}

小易的字典

题目描述
小易在学校中学习了关于字符串的理论, 于是他基于此完成了一个字典的项目。

小易的这个字典很奇特, 字典内的每个单词都包含n个’a’和m个’z’, 并且所有单词按照字典序排列。

小易现在希望你能帮他找出第k个单词是什么。

输入描述: 输入包括一行三个整数n, m, k(1 <= n, m <= 100, 1 <= k <= 109), 以空格分割。

输出描述: 输出第k个字典中的字符串,如果无解,输出-1。

思路:讨论每个位置放a还是z即可

#include <bits/stdc++.h>
#define LL long long 
using namespace std;
const int AX = 1e3 + 6 ;
LL k ; 
LL C( LL n , LL m ){
    if( m == 0 ) return 1 ;
    m = min( m , n - m );
    LL a = 1LL ;
    for( LL i = 1 ; i <= m ; i++ ){
        a =  a * (n - i + 1) ;
        a /= i ; 
        if( a > k ) return -1 ; 
    }
    return a ; 
}
int res[AX] ; 
LL n , m ; 
int main(){
    
    cin >> n >> m >> k ; 
    int na = n ;
    int nz = m ; 
    int f = 1 ; 

    for( int i = 0 ; i < n + m ; i++ ){
        LL ans ; 
        if( na ){
            ans = C( na - 1 + nz , na - 1 ) ; 
            if( ans == -1 || ans >= k ){
				res[i] = 0 ;
				na -- ; 
			}else{
				k -= ans ; 
				ans = C( na + nz - 1 , nz - 1 ) ;
				if( ans == -1 || ans >= k ){
					res[i] = 1 ;  
					nz -- ;
				}else{
					f = 0 ;
					break ;
				}
			}
        }else{
			ans = C( na + nz - 1 , nz - 1 ) ;
			if( ans == -1 || ans >= k ){
				res[i] = 1 ; 
				k -= C( na - 1 + nz , na - 1 );
				nz -- ; 
			}else{
				f = 0 ;
				break ;
			}
		}
    }	
	if(!f) cout << -1 << endl;
	else{
		for( int i = 0 ; i < n + m ; i++ ){
			cout << ( res[i] ? 'z' : 'a' ) ; 
		}
		cout << endl ;
	}
    return 0 ; 
}

代价

题目描述
你有3个需要完成的任务,完成这3个任务是需要付出代价的。
首先,你可以不花任何代价的完成一个任务;然后,在完成了第i个任务之后,你可以花费|Ai - Aj|的代价完成第j个任务。|x|代表x的绝对值。
计算出完成所有任务的最小代价。
输入描述:
一行3个整数A1,A2,A3,每个数字之间用一个空格分隔。所有数字都是整数,并且在[1,100]范围内。
输出描述:
一个整数,代表最小的代价。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int main(){
    int a[5] ; 
    for( int i = 0 ; i < 3 ; i++ ){
        cin >> a[i] ; 
    }
    sort( a , a + 3 ) ; 
    cout << a[2] - a[0] << endl ;  
    return 0 ; 
}

访友

题目描述 小易准备去拜访他的朋友,他的家在0点,但是他的朋友的家在x点(x >
0),均在一条坐标轴上。小易每一次可以向前走1,2,3,4或者5步。问小易最少走多少次可以到达他的朋友的家。 输入描述:
一行包含一个数字x(1 <= x <= 1000000),代表朋友家的位置。 输出描述: 一个整数,最少的步数。

贪心

#include <bits/stdc++.h>
using namespace std;
int main(){
    int x ;
    cin >> x ; 
    int a[10] = { 1 , 2 , 3 , 4 , 5 } ;
    int res = 0 ;
    for( int i = 4 ; x && i >= 0 ; i-- ){
        int tmp = x / a[i] ; 
        x -= tmp * a[i] ; 
        res += tmp ; 
    }
    cout << res << endl; 
    return 0 ; 
}

翻转翻转

题目描述
给定一个N*M的矩阵,在矩阵中每一块有一张牌,我们假定刚开始的时候所有牌的牌面向上。
现在对于每个块进行如下操作:
翻转某个块中的牌,并且与之相邻的其余八张牌也会被翻转。
XXX
XXX
XXX
如上矩阵所示,翻转中间那块时,这九块中的牌都会被翻转一次。
请输出在对矩阵中每一块进行如上操作以后,牌面向下的块的个数。
输入描述:
输入的第一行为测试用例数t(1 <= t <= 100000),
接下来t行,每行包含两个整数N,M(1 <= N, M <= 1,000,000,000)
输出描述:
对于每个用例输出包含一行,输出牌面向下的块的个数
这个题后台数据错了,只能过90%数据

#include <bits/stdc++.h>
using namespace std;
int main(){
    int T ;
    cin >> T ;
    long long n , m ; 
    while( T-- ){
        cin >> n >> m ; 
        if( n >= 2 && m >= 2 ){
            cout << 1LL * ( n - 2 ) * ( m - 2 ) ;
        }else{
            if( n == 1 && m == 1 ){
                cout << 1 ;
            }else{
                if( n == 1 ){
                    cout << m - 2 ; 
                }else{
                    cout << n - 2 ;
                }
            }
        }
        if( T ) cout << endl ; 
    }
    return 0 ; 
}

买房

题目描述
在一条街上有n幢房子,标号从1到n,两个在标号上相差为1的房子视为相邻,这些房子中有k幢房子已有住户。
现你准备搬入这条街,你能搬入一幢房子的条件是这幢房子没有人住在里面,与此同时由于你非常热爱与邻居进行交流,故而你需要你所入住的房子两边上都有住户。
现要你求最小的可能符合要求的房子数,以及最大的可能符合要求的房子数。

Note: 就样例来说,#代表已有住户,-代表空位,这种情况(###—),没有满足条件的房子,为最小,故输出0
最大的情况为(#-#-#-),此种情况有二个位置满足条件,为最大,故输出2 输入描述: 输入的一行为测试用例数t(1 <= t <=
200000),

接下来t行,每行含两个整数n和k,(1 <= n <= 1,000,000,000,0 <= k <= n) 输出描述:
对于每个用例输出最小的可能数以及最大的可能数

#include <bits/stdc++.h>
using namespace std;
int main(){
    int T ;
    cin >> T ; 
    int n , k ;
    while( T-- ){
        cin >> n >> k ; 
        int minu , maxn ;
        minu = 0 ;
        if( n <= 2 || k < 2 || n == k ) maxn = 0 ; 
        else{
            maxn = min( n - k , k - 1 ) ; 
        }
        cout << minu << ' ' << maxn << endl;
    }
    return 0 ; 
}

香槟塔

题目描述
节日到啦,牛牛和妞妞邀请了好多客人来家里做客。
他们摆出了一座高高的香槟塔,牛牛负责听妞妞指挥,往香槟塔里倒香槟。
香槟塔有个很优雅的视觉效果就是如果这一层的香槟满了,就会从边缘处往下一层流去。
妞妞会发出两种指令,指令一是往第x层塔内倒体积为v的香槟,指令二是询问第k层塔香槟的体积为多少。
告诉你香槟塔每层香槟塔的初始容量,你能帮牛牛快速回答妞妞的询问吗?
输入描述:
第一行为两个整数n,m。表示香槟塔的总层数和指令条数。
第二行为n个整数ai,表示每层香槟塔的初始容量。
第三行到第2+m行有两种输入,一种输入是“2 x v”表示往第x层倒入体积为v的香槟;另一种输入是“1 k”表示询问第k层当前有多少香槟。
1 <= n, m <= 1000。
1 <= n ,m <= 200000,1 <= ai ,v <= 1000000000。
输出描述:
对于每个询问,输出一个整数,表示第k层香槟的容量。

思路:线段树维护区间剩余容量和,查询操作直接输出,
从x层倒入操作则二分查找倒入的液体能到达的层数r,此时x到r-1层剩余容量为0,故区间更新为0,
单点更新r层剩余容量 = x到r层总容量tmp - 导入液体总体积val

#include <bits/stdc++.h>
#define lc rt << 1 
#define rc rt << 1 | 1  
#define LL long long 
using namespace std;
const int AX = 2e5 + 666 ; 
LL s[AX<<2] ; // 维护各层剩余容量和 
int lazy[AX<<2];
LL v[AX] ; 
int n , m ; 
LL left_v , tmp ;
 
void pushUp( int rt ){
    s[rt] = s[lc] + s[rc];
    return ;
}
 
void pushDown( int rt ){
    if( lazy[rt] != -1 ){
        s[lc] = s[rc] = 0 ; 
        lazy[lc] = lazy[rc] = 1 ;
        lazy[rt] = -1 ;
    }
    return ; 
}
 
void build( int rt , int l , int r ){
    if( l == r ){
        scanf("%lld",&s[rt]);
        v[l] = s[rt] ;
        return ;
    }
    int mid = ( l + r ) >> 1 ; 
    build( lc , l , mid );
    build( rc , mid + 1 , r );
    pushUp(rt);
}
 
void update( int rt , int l , int r , int L , int R , int op ){
    if( L > r || R < l ) return ; 
    if( L <= l && R >= r ){
        if( op ){
            s[rt] = 0 ; 
            lazy[rt] = 1 ;
        }else s[rt] = left_v ;
        return ; 
    }
    int mid = ( l + r ) >> 1 ; 
    pushDown( rt ) ; 
    if( l <= mid ) update( lc , l , mid , L , R , op );
    if( R > mid ) update( rc , mid + 1 , r , L , R , op );
    pushUp(rt) ; 
}
 
LL query( int rt , int l , int r , int L , int R ){
    if( L <= l && R >= r ) return s[rt] ; 
    int mid = ( l + r ) >> 1 ;
    LL ans = 0 ;
    pushDown( rt );
    if( L <= mid ) ans += query( lc , l , mid , L , R ) ;
    if( R > mid ) ans += query( rc , mid + 1 , r , L , R );
    return ans ; 
}
 
int getR( int l , int r , int x , int val ){ // 查找从x层倒,能满(四声)到哪一层为止
    while( l <= r ){
        int mid = ( l + r ) >> 1 ; 
        if( query( 1 , 1 , n , x , mid ) >= val ) r = mid - 1; 
        else l = mid + 1 ; 
    }
    tmp = query( 1 , 1 , n , x , l );  //查询被倒入液体触及的所有层总容量
    return l ; 
}
 
int main(){
    memset( lazy , -1 , sizeof(lazy) );
    cin >> n >> m ; 
    build( 1 , 1 , n ) ; 
    int op , x ; 
    LL val ; 
    while( m-- ){
        scanf("%d",&op);
        if( op == 1 ){
            scanf("%d",&x);
            printf("%lld\n",v[x] - query( 1 , 1 , n , x , x ) );
        }else{
            scanf("%d%lld",&x,&val);
            int r = getR( x , n , x , val ) ;
            left_v = tmp - val ; 
            if( left_v <= 0 ){ //正好倒满或倒满地上了
                update( 1 , 1 , n , x , r , 1 );
            }else{
                if( r == 1 ) update( 1 , 1 , n , 1 , 1 , 0 ); //第一层都倒不满
                else{  //x到r-1层被倒满,剩余体积设为0,r层剩余left_v体积 = tmp(x到r层总容量)-val(总共倒入体积)
                    update( 1 , 1 , n , x , r - 1 , 1 ) ;
                    update( 1 , 1 , n , r , r , 0 );
                }
            }
        }
    }
    return 0 ; 
}

社团主席选举

题目描述
随着又一届学生的毕业,社团主席换届选举即将进行。

一共有n个投票者和m个候选人,小易知道每一个投票者的投票对象。但是,如果小易给某个投票者一些糖果,那么这个投票者就会改变他的意向,小易让他投给谁,他就会投给谁。

由于小易特别看好这些候选人中的某一个大神,这个人的编号是1,所以小易希望能尽自己的微薄之力让他当选主席,但是小易的糖果数量有限,所以请你帮他计算,最少需要花多少糖果让1号候选人当选。某个候选人可以当选的条件是他获得的票数比其他任何候选者都多。

输入描述: 第一行两个整数n和m,表示投票者的个数和候选人的个数。
接下来n行,每一行两个整数x和y,x表示这个投票者的投票对象,y表示需要花多少个糖果让这个人改变意向。 满足1 <= n, m <=
3000,1 <= x <= m,1 <= y <= 109。 输出描述: 一个整数,糖果的最小花费。

/*
枚举最终需要x票,设原来1号得票数为a;
首先,将>=x票的人多余的票(比x-1多的部分)全买回来,当然从低价买,总共买了tmp票
1.tmp+a > x ;说明x票不成立,因为想赢必须将所有人的多余的票都买回来
2.tmp+a == x ;直接存起来
3.tmp+a < x ; 票还不够,那么就从低价买(没有买过的),直到买够x票,存起来花费
最后输出最少花费
*/
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int AX = 3e3 + 66 ;
typedef pair<int,int>P;
int vto1 ;
int tot ;
set<LL>res ;
int n , m ;
struct Vot{
    int to ;  //支持的人
    LL v ;    // 收买价格
    int id ;  // 投票人id
    Vot(){}
    Vot( int to , LL v , int id ):to(to),v(v),id(id){}
    bool operator < ( const Vot &a )const{
        return v < a.v ;  //按收买价格从小到大排序
    }
}a[AX] ;
struct Can{
    int num ; //支持者数
    int id ;  //候选人id
    Vot cost[AX] ; //支持者
    Can(){ num = 0 ;}
    bool operator < ( const Can &a )const{
        return num > a.num ;  //按支持数从小到大排序
    }
}c[AX] ;
 
void check( int x ){
    map<P,int> mp ;
    LL ans = 0 ;
    int tmp = 0 ;
    for( int i = 2 ; i <= m ; i++ ){ // 大于x-1票的全买过来
        if( c[i].num >= x ){
            int k = c[i].num - x + 1 ;
            tmp += k ;
            for( int j = 0 ; j < k ; j++ ){
                ans += c[i].cost[j].v ;
                mp[P(c[i].cost[j].id,c[i].cost[j].to)] = 1 ;
            }
        }else break ;
    }
     
    if( tmp + vto1 > x ) return ;
    else if( tmp + vto1 == x ) res.insert(ans);
    else{
        for( int i = 0 ; i < tot ; i++ ){
            if( tmp + vto1 >= x ) break ;
            if( !mp[P(a[i].id,a[i].to)] ){
                tmp ++ ;
                ans += a[i].v ;
            }
        }
        res.insert(ans);
    }
    return ;
}
int main(){
     
    scanf("%d%d",&n,&m);  //投票者的个数n   候选人的个数m
    vto1 = 0 ;
    tot = 0 ;
    int x ;
	LL y ;
    for( int i = 1 ; i <= n ; i++ ){
        scanf("%d%lld",&x,&y) ; //i投给x,收买要y
        if( x != 1 ){
            a[tot++] = Vot(x,y,i) ;
        }else vto1 ++ ;
        c[x].cost[c[x].num++] = Vot(x,y,i) ;//候选人x的支持者集合
    }
    for( int i = 1 ; i <= m ; i++ ) c[i].id = i ; //候选者id
    sort( a , a + tot ) ;  //投票人按收买价格排序
    sort( c + 2 , c + m + 1 ) ; //候选人按支持数
    for( int i = 2 ; i <= m ; i ++ ){
        sort( c[i].cost , c[i].cost + c[i].num ) ;  //投票人按收买价格排序
    }
 
    for( int i = 1 ; i <= n ; i++ ){
        check(i) ;
    }
    cout << *res.begin() << endl ;
    return 0 ;
}

橡皮泥斑马

题目描述
小易很喜欢斑马,因为它们身上黑白相间的花纹。
一天小易得到了一串橡皮泥,这串橡皮泥只有黑色和白色,小易想把这串橡皮泥重新拼凑一下,让这个橡皮泥串中最长的连续的黑白相间的子串最长,但是小易有强迫症,所以他可以对橡皮泥串进行以下的操作0次或多次:
把橡皮泥串从某个地方切割开,将两个得到的两个串同时翻转,再拼接在一起。
这个橡皮泥串可能太长了,所以小易没有办法计算最终可以得到的最长的连续的黑白相间的子串的长度,希望你能帮他计算出这个长度。
输入描述:
一个字符串s,只包含字母’b’和字母’w’,分别表示黑色和白色的橡皮泥块。
满足1 <= |s| <= 105,|s|代表字符串的长度。
输出描述:
一个整数,表示改变之后最长的连续的黑白相间的子串的长度。

/*切割并同时旋转拼接 相当于 把切割后 后面的子串 放到 前面 
如wbwwb,切割wbw,wb 后放前 -> wbwbw 与翻转(wbw,bw)后拼接结果一致
故将原字符串扩大2倍,找最长相间子串
*/
#include <bits/stdc++.h>
using namespace std;
int main(){
    string s ; 
    cin >> s ; 
    s += s ;
    int len = s.size() ;
    int res = 0 ; 
    for( int i = 0 ; i < len ; i++ ){
        int j = i + 1 ;
        while( j < len && s[j] != s[j-1] ){
            j ++ ;
        }
        res = max( res , j - i ) ; 
        i = j - 1 ;
    }
    cout << min( res , len / 2 ) << endl ;
    return 0 ; 
}

篮球队

题目描述
小Q是篮球训练队的教练,篮球队新加入了N名队员,第i名队员的篮球水平值为ai。
小Q现在要把他们按照以下的要求分为A队和B队进行训练:
1、A队的队员水平值之和严格大于B队的队员水平值之和
2、对于A队中的任意一名队员,如果把他分配到B队,A队的水平值之和就会严格小于B队的水平值之和。
3、每个队员必须要加入一个队伍
小Q现在想知道有多少种方案可以按照以上要求完成分队。
输入描述:
输入包括两行, 输入的第一行为一个正整数n(2 <= N <= 50), 表示队员的数量。
第二行包括N个正整数 ai(1 <= ai <= 6 x 104), 表示每名队员的篮球水平值, 以空格分割。
输出描述:
输出一个正整数, 表示方案数。

思路:A队和Sa,B队和Sb,寻找满足Sa>Sb && Sa - a[i] < Sb + a[i]的方案数 ,其中a[i]为Sa中最小值;
故可枚举a[i],计算当Sa中最小值为a[i]时各Sa的方案数dp[Sa]。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int AX = 3e6 + 666 ;
int a[AX] ;
int n , S ;
LL res ; 
LL dp[AX] ;
int main(){
    cin >> n ;
    S = 0 ; 
    res = 0 ;
    for( int i = 0 ; i < n ; i++ ){
        cin >> a[i] ; 
        S += a[i] ; 
    }
    memset( dp , 0LL , sizeof(dp) ) ; 
    sort( a , a + n ) ; 
    dp[0] = 1 ; 
    for( int i = n - 1 ; i >= 0 ; i-- ){ //Sa_min
        /*从大到小枚举Sa最小值,因为每次都要保证小于a[i]的Sa值的方案数dp[Sa]=0
        (因为a[i]是目前Sa的最小值,小于其的Sa方案数只能为0)*/
        for( int j = S ; j >= a[i] ; j-- ){ // 0-1:装满Sa方案数
            dp[j] += dp[j-a[i]] ; 
            int Sb = S - j ; 
            /*若满足Sa>Sb && Sa-a[i]<Sb+a[i],方案++*/
            if( j > Sb && j - a[i] < Sb + a[i] ) res += dp[j-a[i]] ; 
        }
    }
    cout << res << endl; 
    return 0 ; 
}

字母卡片

题目描述
给你n张卡片,卡片上仅包含大写英文字母,现你可从这n张卡片中选出k张,要求得到尽可能高的分数。
关于分数的计算方式,在你所选择的k张卡片中,含有相同字母的卡片分数为卡片数乘以相同卡片个数。
就样例而言,选择九张D和其他任意一张,得到的结果为9*9+1 。
输入描述:
输入包含两行,第一行含两个整数n,k(0<k<=n<=1,000,000)

第二行为每张卡片上的字母 输出描述: 输出仅包含一行,输出尽可能高的分数

#include <bits/stdc++.h>
#define LL long long 
using namespace std ;
int main(){
    LL a[30] ; 
    string s ; 
    int n , k ; 
    while( cin >> n >> k ){
        cin >> s ;
        memset( a , 0 , sizeof(a) ) ; 
        for( int i = 0 ; i < n ; i++ ){
            a[(int)s[i]-'A'] ++ ;
        }
        sort( a , a + 26 ) ; 
        LL res = 0 ;
        for( int i = 25 ; i >= 0 ; i-- ){
            LL v = min( (LL)k , a[i] ) ;
            res += v * v ; 
            k -= v ; 
        }
        cout << res << endl ;   
    }
    return 0 ; 
}

相等序列

题目描述
题目给定a1,a2…an,这样一个长度为n的序列,现在你可以给其中一些元素加上一个值x(只能加一次),然后可以给另外一些值减上一个值x(只能减一次),剩下的元素不能再进行操作。问最后有没有可能找到一个值x使所有元素的值相等。
输入描述:
输入第一行为一个整数k,代表有k个序列(k<100),接下来有2*k行:
偶数行为一个整数n,代表给定序列的长度(1<=n<=100,000)
奇数行包含n个元素,a1,a2…an,代表序列中的元素(0<=ai<=100,000)

输出描述: 输出k行,每行一个YES或者NO

去重,剩下大于3个数就不行,2个肯定行,3个就判断最大最小距离中间数值距离是否相等。

#include <bits/stdc++.h>
using namespace std;
int main(){
    int T ;
    cin >> T ;
    int n ;
    
    while( T-- ){
        vector<int>v ; 
        cin >> n ; 
        int x ; 
        for( int i = 0 ; i < n ; i++ ){
            cin >> x ; 
            v.push_back(x) ; 
        }
        sort( v.begin() , v.end() ) ;
        int len = unique( v.begin() , v.end() ) - v.begin() ;
        if( len > 3 ){
            cout << "NO" << endl;
        }else{
            if( len == 1 ) cout << "YES" << endl ; 
            if( len == 3 ){
                if( v[1] - v[0] == v[2] - v[1] ){
                    cout << "YES" << endl ;
                }else cout << "NO" << endl ; 
            }
            if( len == 2 ){
                cout << "YES" << endl;
            }
        }
    }
    return 0 ; 
}

N-GCD

题目描述 小明很喜欢数对,又很喜欢GCD(最大公约数)。所以他想尽办法创造了一种全新的最大公约数:
给出若干个数对(ai,bi),如果一个最大的质数x可以整除每一个数对中的至少一个数字并且这个数字大于1,那么x就称为这些数对的N-GCD。
现在小明给了你一些数对,希望你可以算出它们的N-GCD。 输入描述:

第一行一个数字n,表示数对的个数。

接下来n行,每行两个数字,用一个空格分隔,表示一个数对。

满足1<=n <=150000,1<=ai,bi<=2 * 10^9。
输出描述: 一个数字,这些数对的N-GCD;若N-GCD不存在,那么输出-1。

/*对任意一组分解质因数(这里选和最小的),遍历所有组,不满足条件(整除任意组的至少一个数)的删除
最后看剩下的有无,没有-1.有输出最大的*/
#include <bits/stdc++.h>
#define LL long long 
using namespace std;
const int AX = 2e5 + 666 ; 
struct Node{
    LL x ;
    LL y ;
    bool operator < ( const Node &a )const{
        return ( x + y ) < ( a.x + a.y ) ; 
    }
}a[AX];
set<LL>s ;

void get_PrimeFac( LL x ){
    for( LL i = 2 ; i * i <= x ; i++ ){
        if( x % i == 0 ){
            s.insert(i) ; 
            while( x % i == 0 ){
                x /= i ;
            }
        }
    }
    if( x > 1 ) s.insert(x) ; 
}

int main(){
    int n ;
    scanf("%d",&n) ;
    LL x , y ; 
    for( int i = 0 ; i < n ; i++ ){
        scanf("%lld%lld",&a[i].x,&a[i].y) ; 
    }
    sort( a , a + n ) ; 
    get_PrimeFac(a[0].x);
    get_PrimeFac(a[0].y);
    set<LL>::iterator it , tmp ;
    
    if( s.size() ){
        for( int i = 1 ; i < n ; i++ ){
            it = s.begin() ; //放错位置找了半天- -。
            while( it != s.end() ){
                if( ( a[i].x % (*it) ) && ( a[i].y % (*it) ) ){
                    tmp = it ;
                    it++ ; 
                    s.erase(tmp) ;
                }else it++ ; 
            } 
        }   
    }
    if( !s.size() ){
        cout << -1 << endl;
    }else{
        it = s.end() ; it--;
        cout << *it << endl;
    }
    return 0 ; 
}

分贝壳

题目描述
牛牛和妞妞去海边捡了一大袋美丽的贝壳,千辛万苦地运回家后,牛牛和妞妞打算分掉这些贝壳。
牛牛提出,他和妞妞轮流从还没有分配的贝壳中取一定数量的贝壳,直到贝壳分完为止。分配规则是牛牛每次取剩余贝壳的1/10(向下取整),妞妞每次固定取m个贝壳,妞妞先取。
妞妞想要得到不少于一半的贝壳,又不想太过分,那么她一次最少取多少个贝壳才能得到不少于一半的贝壳呢?
输入描述:
一个正整数n,表示贝壳的总数量,1<=n<=1000000000000000000。
输出描述:
一个正整数m,表示妞妞一次最少取的贝壳数量。

二分一次取得贝壳数量

#include <bits/stdc++.h>
#define LL long long 
using namespace std;
LL n ;
bool solve( LL m ){
    LL ans1 = 0 ;
    LL ans2 = 0 ;
    LL v ; 
    LL t = n ; 
    while( t > 0 ){ 
        v = min( t , m ) ; 
        t -= v ;
        ans1 += v ; 
        LL tmp = t / 10 ;
        ans2 += tmp ;
        t -= tmp ;  
    }
    return ( ans1 >= ans2 ) ;
}
int main(){
    cin >> n ; 
    LL l = 1 , r = n ;
    while( l <= r ){
        LL mid = ( l + r ) >> 1 ;
        if( solve(mid) ) r = mid - 1 ; 
        else l = mid + 1 ; 
    }
    cout << l << endl ; 
    return 0 ; 
}

美妙的约会

题目描述
牛牛和妞妞在一天晚上决定一起去看一场情人节演唱会,可是由于这场演唱会实在太出名了,有很多情侣都来观看,牛牛和妞妞不小心被人流冲散了!
维持秩序的人决定,让大家排成一列,相邻两个进去的人(2k-1和2k,k为正整数)坐在相邻座位。但是现在的队伍乱糟糟的,有很多情侣都不在相邻位置。维持秩序的人同意让情侣们跟相邻的人交换位置,直到所有情侣都在2k-1和2k位置上为止。
但是维持秩序的人很没有耐心,所以需要最少的交换次数,你能帮情侣们算出这个次数吗?
输入描述:
第一行一个整数n,表示一共有n对情侣,编号从1到n。同一对情侣编号相同。1<=n<=100
第二行2n个整数ai,表示编号为ai的情侣在第i个位置。1<=ai<=n
输出描述:
一个整数,代表最少交换次数。

/*用id标识每个人实际位置,枚举每个人,寻找其情侣的位置,将靠后的情侣换过来
(两者之间人的id都+1,相当于后移一位)
*/
#include <bits/stdc++.h>
using namespace std;
const int AX = 1e2 + 66 ;
struct Node{
    int id ; 
    int v ; 
}a[AX];
map<int,int>mp ; 
int main(){
    int n ;
    cin >> n ; 
    int res = 0 ;
    int len = 2 * n ; 
    for( int i = 1 ; i <= len ; i++ ){
        cin >> a[i].v ;
        a[i].id = i ;
    }
    for( int i = 1 ; i < len ; i++ ){
        mp[a[i].v] = 1 ;
        for( int j = i + 1 ; j <= len ; j++ ){
            if( a[j].id < a[i].id ) continue ;
            if( mp[a[j].v] ){
                res += ( abs( a[j].id - a[i].id ) - 1 ) ; 
                for( int k = 1 ; k <= len ; k++ ){
                                        //两者之间人位置后移一位
                    if( a[j].id > a[k].id && a[k].id > a[i].id ) a[k].id ++ ; 
                }
                a[j].id = a[i].id + 1 ; //修改靠后情侣实际位置
                break ; 
            }
        }
        mp[a[i].v] = 0 ;
    }
    cout << res << endl ; 
    return 0 ; 
}

模数求和

题目描述 现给定n个整数,并定义一个非负整数m,且令f(m) = (m%a1)+(m%a2)+…+(m%an)。 此处的X %
Y的结果为X除以Y的余数。 现请你找出一个m,求出f(m)的最大值。

输入描述: 输入包含两行,第一行为一正整数n,(1<n<=3000) 第二行为n个整数a1,a2,…,an
,其中(2<=ai<=10^5) 输出描述: 输出仅包含一行,输出f(m)的最大值

模数最大是ai-1,加和即可。

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n ;
    cin >> n ;
    int x ;
    int s = 0 ; 
    for( int i = 0 ; i < n ; i++ ){
        cin >> x ; 
        s += x ;
    }
    cout << s - n << endl ; 
    return 0 ; 
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值