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 <cstdio>
#include <cstring>
#include<iostream>
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++;elser--;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");elseprintf("%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<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
#include <list>
using namespace std;
typedef long long ll ;
typedef unsigned long long ull ;
#define pii pair<int,int>
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,那么无解,等于k一定有解
,现在就是k<sum是否一定有解..
答案是一定的..(贪心)
我们可以构造下降+上升的一段
比如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<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
#include <list>
using namespace std;
typedef long long ll ;
typedef unsigned long long ull ;
#define pii pair<int,int>
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];
vector<int>a,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]<k){printf("-1\n");return 0;}for(int i=n;i>=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<a.size();i++)cout<<a[i]<<" ";for(int i=0;i<b.size();i++)cout<<b[i]<<" ";printf("\n");return 0;
}