暑假集训笔记

Problem - B - Codeforces

这题看了好久,一直没思路..也可能是早上来没睡醒的原因吧.有点困..

昨天晚上12点睡的,然后早上直接睡到7.48....真的6啊

话说这题真有点猜的成分,

先说我的思路:一开始和的奇偶

如果为偶数:那么分的所有部分的和一定都为偶数才有利

如果为奇数:那么分的所有部分的和一定为奇数才对答案有利

但是这个奇数和和偶数和非常难找....

(蚌埠住了...今天出了百度之星成绩极其的拉跨.....感觉比赛的时候感觉自己啥也不会....我是菜鸡..,感觉自己还是有实力的,但就是自己暑假集训的状态极其的差啊!!!)

正解:

要使分裂的部分的最大公约数最大,分裂的部分一定为2个

证明如下:

设如果k大于2的话,答案为ans=gcd(b1,b2,b3...bk),因为b1和b2一定为ans的倍数,并且a1+a2也一定为ans的倍数且不会使答案更坏

所以gcd(b1+b2,b3,b4,bk)一定优于gcd(b1,b2,b3,b4,bk)

Contest Login

昨天航电的一道博弈论题目 ,昨天做的时候就感觉没有啥思路...今天也没啥思路..队内大腿队友还是强啊!!

正解:设现在x先手

1.如果两边都为!x,那么x输

2.如果两边为!x和x,那么x只能选x,x不具有主动权,两者向内推进

3.如果两边为x和x,那么x可以选任意一边,!x只能跟着x操作,即x具有主动权,可以发现x胜利的话,必须至少有2个连续的x,还有我们需要特判下出现2个!x!x的情况(此情况可能是平局!!)比如字符串为010101101010,从左到右的话,0在7位置受阻,从右到左的话,0在6位置受阻,此时为平局!!

#include 
#include 
#include
using namespace std;
const int N = 1e6 + 2;

int t, n, l, r, now;
char s[N];

void firstchk() {
    while(l < r && s[l] != s[r]) {
        if(s[l] == now)
            l++;
        else
            r--;
        now ^= 1;
    }
    if(l == r && s[l] == now)
        l++;
}

int chkl(int n) {
    for (int i = l; i <= r; i++) {
        if(n != s[i])
            return i;
        n ^= 1;
    }
    return -1;
}

int chkr(int n) {
    for (int i = r; i >= l; i--) {
        if(n != s[i])
            return i;
        n^= 1;
    }
    return -1;
}

int main() {
	
    scanf("%d", &t);
    
    while(t--) {
        now = 0;
        scanf("%d%s", &n, s + 1);
        
       for (int i = 1; i <= n; i++){
        	s[i] = s[i]&1;
		}    
       
        l = 1, r = n;
        firstchk();
        
        if(l > r) {
            puts("-1");
            continue;
        }
        
        if(s[l] != now) {
            printf("%d\n", now ^ 1);
            continue;
        }
        
        int lpos = chkl(now);
        int rpos = chkr(now);
        if(lpos != -1 && s[lpos] == now || rpos != -1 && s[rpos] == now)
            printf("%d\n", now);
        else if(rpos + 1 == lpos || lpos == -1)
            puts("-1");
        else
            printf("%d\n", s[lpos]);
    }
    return 0;
}

 这个好像将0和1的字符可以直接和(0和1)比较

 for (int i = 1; i <= n; i++){
        	s[i] = s[i]&1;
		}    

今天下午又刷了一套小白月赛的题目,感觉题目质量还是很高的!

登录—专业IT笔试面试备考平台_牛客网

这题直接set+二分就出来了,但是tm的题目有毒啊!!

必须关闭网络流并且不能用endl!!不然我早就过了!!

登录—专业IT笔试面试备考平台_牛客网

一道博弈论的题目...比赛时候没有做出来,自己太菜了....

比赛结束后一共过了500多个人....

感觉还是自己太菜了....

比赛的时候没太有思路,就开始乱想了....

看了题解感觉确实牛..

考察点:思维,博弈,对称策略(模拟棋)

1.给带的a,b2个数,如果a,b的最小值模3==0,那么后手赢

证明如下:

假设给定 9 11,无论先手怎样操作,后手都可以根据先手下模拟棋子,

将其变为6   8,然后循环,最后先手得到0 2,先手输

2.如果a,b的最小值模3!=0,如果模数为1,并且a==b,那么后手赢

证明如下:

给定 10 10,设最小值为第一位,第一轮先手 9  8,(此时最小值位置发生改变)第二轮后手可以将其变成 8 6,然后再根据先手下模拟棋,

后手赢

3.其他情况先手赢

证明(a=b&&min(a,b)%3==2)先手赢

证明如下:

给定11 11,第一轮操作为 9 10,后手无论如何也不能改变最小值的位置

然后先手可以根据后手下模拟棋

所以先手赢

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include 
#include 
using namespace std;
typedef  long  long ll ;
typedef  unsigned long  long ull ;
#define pii pair
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
int t;
int main(){
	
	scanf("%d",&t);
	
	while(t--){
		ll a,b;
		scanf("%lld%lld",&a,&b);
		
		if(a==1&&b==1){
			printf("niumei\n");
			continue;
		}
		
		if(a<=2||b<=2){
			printf("niuniu\n");
			continue;
		}
		
		
		ll c=min(a,b);
		int r=c%3;
		
		if(r==0){
			printf("niumei\n");
			
		}else{
			
			if(r==1&&a==b){
				printf("niumei\n");
			}else{
				printf("niuniu\n");
			}
			
		}
			
	}
	return 0;
}


登录—专业IT笔试面试备考平台_牛客网

一道感觉比较难的构造吧...

我想了想,没有想到如何分块的方法..

比如54321  987 10 11 12 13 14

然后看了题解感觉挺简单的...
我们设f[x]为x对x-1 x-2 x-3 x-4 3 2 1 的贡献,显而易见f[x]=log2(x-1)+1

然后我们就可以我们可以以O(n)统计每一个的f[i],如果总的f[i]和

,现在就是k

答案是一定的..(贪心)

我们可以构造下降+上升的一段

比如7 6 5  3 1 2 4,这一段的贡献总和为f[7]+f[6]+f[5]+f[3]

如果当前的f[i]<=k我们就然k-f[i]

for(int i=n;i>=1;i--){
		if(f[i]<=k){
			a.push_back(i);
			k=k-f[i];
		}else{
			b.push_back(i);
		}
	}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include 
#include 
using namespace std;
typedef  long  long ll ;
typedef  unsigned long  long ull ;
#define pii pair
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
int n,k;
ll f[1000006];
ll sum[1000006];
vectora,b;
int main(){
	
	scanf("%d%d",&n,&k);
	
	f[1]=0;
	
	for(int i=2;i<=n;i++){
		 f[i]=log2(i-1)+1;
	}
	
	for(int i=1;i<=n;i++){
		sum[i]=sum[i-1]+f[i];
	}
	
	if(sum[n]=1;i--){
		if(f[i]<=k){
			a.push_back(i);
			k=k-f[i];
		}else{
			b.push_back(i);
		}
	}
	
	if(k){
		printf("-1\n");
		return 0;
	}
	
	reverse(b.begin(),b.end());
	
	for(int i=0;i

你可能感兴趣的:(笔记,算法,c++)