【AtCoder】【AGC010D】Decrementing

本文探讨了一个关于两人轮流操作的博弈论游戏。游戏的目标是避免将序列和变为等于序列长度的情况。文章给出了针对不同序列长度和序列总和的奇偶性的获胜策略,并通过代码实现了这些策略。

Description

给出一个长度为n的序列 a a ,A、B两个人轮流操作:
1. 选择一个不为1的数,将其-1;
2. 把序列中的所有数/g,g为所有数的gcd;

操作不了的人输。

Solution

博弈题一堆结论…

输的人肯定是拿到111111的局面,
设sum为序列所有数的和,
要想赢,肯定要避免拿到sum=n的情况,

当n为偶数时:如果一直拿到sum为奇数的情况,那么必赢,

结论1:n为偶数且sum为奇数时,先手必胜,否则必输;

我们先来看一下sum在经历了一次操作后的奇偶变化:

(图片来源,侵删)
这里写图片描述

显然,先手可以让每一轮操作后都留给对手一个偶数,而对手只能还回来一个奇数,所以必赢;

偶数必输显然;

当n为奇数时:
结论2:n为奇数且sum为偶数时,先手必胜;
证明:先手要想赢,就必须不让对手还回来一个奇数,对手要想还回来一个奇数,就必须保证gcd不为0,
也就是说,对手在操作前,序列中所有数%gcd是这样的:0,0…,0,1
所以先手只要避免这种情况即可,那先手操作前的序列%gcd有这几种情况:
0,0,0,0,2
0,0,0,1,1
0,0,0,0,k+1
0,0,0,1,k
(后两个要除以那一局的gcd)

我们发现,这4种情况均可以破解,使之不变成0,0,0,0,1,

结论2:n为奇数且sum为奇数时,先手不一定输;
例:2,2,3,这样的话先手必赢,

先手肯定是必须给对手一个奇数,否则对手就赢了
所以就判断能否给对手一个奇数,显然每局如果可以的话方案唯一,
不行当前的人输
每次的gcd必须>1,所以是log次的。

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;
const int N=100500;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans;
int a[N];
int g[N];
int gcd(int x,int y){return y?gcd(y,x%y):x;}
int main()
{
    int w;
    LL q;
    read(n);
    fo(i,1,n)q+=(LL)read(a[i]);
    if(n==1&&a[1]==1)return printf("Second\n"),0;
    if(n==1)return printf("First\n"),0;
    if(!(n&1))
    {
        if(q&1)printf("First\n");
        else printf("Second\n");
        return 0;
    }
    if(!(q&1))return printf("First\n"),0;
    for(bool I=0;1;I=!I)
    {
        g[n]=a[n];
        LL t=a[n]-1;
        fod(i,n-1,1)g[i]=gcd(g[i+1],a[i]),t+=(LL)a[i];
        bool OK=0;
        q=a[1];
        if(a[1]-1&&(1&(t/(ans=gcd(g[2],a[1]-1)))))OK=1,--a[1];
        else fo(i,2,n)if(a[i]-1)
        {
            w=gcd(q,a[i]-1);
            if(i<n)w=gcd(w,g[i+1]);
            if((1&(t/(ans=w))))
            {
                OK=1,--a[i];
                break;
            }
            q=gcd(q,a[i]);
        }else break;
        if(!OK)
        {
            if(I)printf("First\n");
            else printf("Second\n");
            return 0;
        }
        fo(i,1,n)a[i]/=ans;
    }
    return 0;
}
The following is an AVR code example using the C programming language for the Elegoo R3 UNO Starter kit to make 4 LEDs count up and down in binary from 0 - 15 when the left and right buttons are pressed. ```c #include <avr/io.h> #include <util/delay.h> // Define button pins #define BUTTON_UP_PIN PD2 #define BUTTON_DOWN_PIN PD3 // Define LED pins #define LED_PIN_0 PB0 #define LED_PIN_1 PB1 #define LED_PIN_2 PB2 #define LED_PIN_3 PB3 // Function to set the LEDs based on a 4-bit value void set_leds(uint8_t value) { PORTB = (PORTB & 0xF0) | (value & 0x0F); } // Function to read a button state uint8_t read_button(uint8_t pin) { return (PIND & (1 << pin)) == 0; } int main(void) { // Set LED pins as output DDRB |= (1 << LED_PIN_0) | (1 << LED_PIN_1) | (1 << LED_PIN_2) | (1 << LED_PIN_3); // Set button pins as input with pull-up resistors DDRD &= ~((1 << BUTTON_UP_PIN) | (1 << BUTTON_DOWN_PIN)); PORTD |= (1 << BUTTON_UP_PIN) | (1 << BUTTON_DOWN_PIN); uint8_t counter = 0; while (1) { if (read_button(BUTTON_UP_PIN)) { _delay_ms(20); // Debounce if (read_button(BUTTON_UP_PIN)) { if (counter < 15) { counter++; } while (read_button(BUTTON_UP_PIN)); // Wait for button release } } if (read_button(BUTTON_DOWN_PIN)) { _delay_ms(20); // Debounce if (read_button(BUTTON_DOWN_PIN)) { if (counter > 0) { counter--; } while (read_button(BUTTON_DOWN_PIN)); // Wait for button release } } set_leds(counter); } return 0; } ``` ### Explanation: 1. **Pin Definitions**: The code first defines the pins for the buttons and LEDs. The button pins are on port D, and the LED pins are on port B. 2. **`set_leds` function**: This function takes a 4 - bit value and sets the corresponding LEDs on port B. 3. **`read_button` function**: This function reads the state of a button. It checks if the button is pressed (low logic level) and returns a boolean value. 4. **`main` function**: - It initializes the LED pins as outputs and the button pins as inputs with pull - up resistors. - It enters an infinite loop where it continuously checks the state of the buttons. - When a button is pressed, it debounces the button press to avoid false triggering. - If the up button is pressed and the counter is less than 15, it increments the counter. If the down button is pressed and the counter is greater than 0, it decrements the counter. - After any change in the counter, it updates the LEDs to display the new binary value.
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值