在一个n*m大小的棋盘上,从左下角移动到右上角,每次只能向一个方向移动奇数个格子(向右或向上),最后不能移动的输,B先手,问最后谁赢。
思路:每次移动奇数,那所有奇数的性质相同,偶数性质相同。易得出n和m奇偶性质相同时,T赢,反之则B赢。
AC Code:
- #include
-
- typedef long long ll;
- const int N=1e5+5;
- const int mod=1e9+7;
- int t,n,m;
-
- int main(){
- std::ios::sync_with_stdio(false);
- std::cin.tie(0);
- std::cout.tie(0);
- std::cin>>t;
- while(t--){
- std::cin>>n>>m;
- if(n%2==m%2) std::cout<<"Tonya"<<'\n';
- else std::cout<<"Burenka"<<'\n';
- }
- return 0;
- }
给出n和k,将1~n分为两两一组,并规定其中某个数为a,某个数为b,满足(a+k)*b为4的倍数,问是否存在满足条件的分组方式,有则输出分组方式。
思路:满足是4的倍数,要么两个因数各有2,要么其中一个数为4的倍数,首先k为0一定不行,因为最小的1,2组合需要加入大数才能满足条件;若不为0,则判断是否满足整除4的条件,即交换a和b的值。易得分组为相邻两数两两互组。
AC Code:
- #include
-
- typedef long long ll;
- typedef std::pair<int,int>PII;
- const int N=1e5+5;
- const int mod=1e9+7;
- int t,n,k;
-
- int main(){
- std::ios::sync_with_stdio(false);
- std::cin.tie(0);
- std::cout.tie(0);
- std::cin>>t;
- while(t--){
- std::cin>>n>>k;
- if(k&1){
- std::cout<<"YES"<<'\n';
- for(int i=1;i<=n;i+=2){
- std::cout<' '<1<<'\n';
- }
- }
- else{
- bool flag=true;
- std::vector
ans; - for(int i=1;i<=n;i+=2){
- if((k+i+1)%4==0){
- ans.push_back({i+1,i});
- }
- else if((i+1)%4==0){
- ans.push_back({i,i+1});
- }
- else{
- flag=false;
- break;
- }
- }
- std::cout<<(flag?"YES":"NO")<<'\n';
- if(flag){
- for(int i=0;i
2;i++){ - std::cout<
' '<'\n'; - }
- }
- }
- }
- return 0;
- }
给出n个数,从左侧依次拿出两个数比较,大的留下,小的置于队尾,若某个数大于比较的数,则赢一次,给出比较轮数,q次询问,每次回答每个数赢得次数。
思路: 观察可以发现,一个数会赢的条件是没有遇到比自己大的数;若是整个数组中最大的数,则在开始比较后全赢;若是该数前面存在比它大的数,则一直为0。根据这个条件,分类讨论即可。
AC Code:
- #include
-
- typedef long long ll;
- typedef std::pair<int,int>PII;
- const int N=1e5+5;
- const int mod=1e9+7;
- int t,n,q,id,k;
- int a[N],cnt[N];
-
- int main(){
- std::ios::sync_with_stdio(false);
- std::cin.tie(0);
- std::cout.tie(0);
- std::cin>>t;
- while(t--){
- std::cin>>n>>q;
- memset(cnt,0,sizeof(cnt));
- for(int i=1;i<=n;i++){
- std::cin>>a[i];
- }
- int pos=1,max=a[1];
- for(int i=2;i<=n;i++){
- if(a[i]
0; - else{
- cnt[pos]=i;
- pos=i;
- max=a[i];
- }
- }
- cnt[pos]=-1;
- while(q--){
- std::cin>>id>>k;
- if(cnt[id]==0){
- std::cout<<0<<'\n';
- }
- else if(cnt[id]==-1){
- if(k>=std::max(1,id-1)) std::cout<
max(0,id-1-1)<<'\n'; - else std::cout<<0<<'\n';
- }
- else{
- int max=cnt[id]-1;
- if(k
- if(k
max(1,id-1)) std::cout<<0<<'\n'; - else std::cout<
max(0,id-1-1)<<'\n'; - }
- else{
- std::cout<
max(0,id-1-1)-1<<'\n'; - }
- }
- }
- }
- return 0;
- }
os:WA麻了
D2. Burenka and Traditions (hard version)
给出n个数,每次选择一个x,将一个区间异或x,问最少的操作次数,使得数组全为0。
思路:大佬的思路显然最多的操作数是n,把每一个数都亦或上自己即可。为了尽可能减少操作次数,显而易见的是对于一段连续的相同的数比如2222,我们也可以通过一次操作把他变为0。但是本质其实是对于一个新的数,我们要判断前面的数载操作后能否顺便把这个数也变成0。
我们需要的是在操作一个新数前的所有的后缀异或和。比如一串序列a, b, c。我们在操作a,b后并保证ab都变成0的情况下,c可能的取值是c,b^c,a^b^c,模拟一下即可。那么所有的后缀就是b和a^b,我们用set来维护所有的后缀,然后在枚举新数的时候判断是否出现在后缀里即可。
AC Code:
- #include
-
- int t,n;
-
- int main(){
- std::ios::sync_with_stdio(false);
- std::cin.tie(0);
- std::cout.tie(0);
- std::cin>>t;
- while(t--){
- std::cin>>n;
- std::vector<int>a(n+1,0);
- for(int i=1;i<=n;i++){
- std::cin>>a[i];
- }
- int res=0;
- std::set<int>s;
- s.insert(0);
- int suf=0;
- for(int i=1;i<=n;i++){
- if(s.count(a[i]^suf)||a[i]==0) s.clear(),suf=0;
- else res++,s.insert(suf),suf^=a[i];
- }
- std::cout<
'\n'; - }
- return 0;
- }
os:这思维太顶了