Codeforces 1075 Div2(ABC1C2D1D2)

前言

上大分的一场!加油!!

一、A. Table with Numbers

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF=1e9;
const ll INFLL=1e18;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

void solve()
{
    int n,h,l;
    cin>>n>>h>>l;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }

    if(h>l)
    {
        swap(h,l);
    }

    int no=0;
    int row=0;
    int both=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>l)
        {
            no++;
        }
        else if(a[i]>h)
        {
            row++;
        }
        else
        {
            both++;
        }
    }

    if(row<=both)
    {
        cout<<row+(both-row)/2<<endl;
    }
    else
    {
        cout<<both<<endl;
    }
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

首先,还是先考虑让更大的做宽。那么之后可以发现,对于数组里的数,可以被分为不能被选的 no、只能被选来做宽的 row 和做宽做长都可以的 both。那么在统计出这三种的个数后,若只能用来做宽的个数小于等于两者均可以的,那么肯定是首先选择只能做宽的和都可以的配对,产生 row 点贡献,然后再从剩下的 both 里两两一对产生贡献。否则,即只能用来做宽的大于均可以的,那么就只能让产生 both 点贡献。

二、B. The Curse of the Frog

byd上来题就读了一会,又被贪心策略卡了一会,闹麻了......

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF=1e9;
const ll INFLL=1e18;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

void solve()
{
    ll n,x;
    cin>>n>>x;
    vector<array<ll,3>>jump(n+1);
    for(int i=1;i<=n;i++)
    {
        //a b c
        cin>>jump[i][0]>>jump[i][1]>>jump[i][2];
    }

    ll cur=0;
    for(int i=1;i<=n;i++)
    {
        cur+=(jump[i][1]-1)*jump[i][0];
    }

    if(cur>=x)
    {
        cout<<0<<endl;
        return ;
    }

    vector<array<ll,3>>b;
    for(int i=1;i<=n;i++)
    {
        if(jump[i][0]*jump[i][1]>jump[i][2])
        {
            b.push_back(jump[i]);
        }
    }

    if(b.empty())
    {
        cout<<-1<<endl;
        return ;
    }

    sort(b.begin(),b.end(),[&](auto &x,auto &y)
    {
        return x[0]*x[1]-x[2]>y[0]*y[1]-y[2];
    });

    ll step=b[0][0]*b[0][1]-b[0][2];
    ll rest=x-cur;

    cout<<(rest+step-1)/step<<endl;
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

首先,肯定是可以考虑白嫖每种跳跃的距离,即用每种类型都跳 b[i]-1 次,使得不发生回滚。此时,若已经大于等于终点了,那么直接返回0即可。否则,因为之后再跳就发生回滚了,那么净收益小于等于0的所有类型肯定都不能再用了,因为必然不会导致距离前进。那么若此时不存在收益大于0的跳跃,就不可能达到。之后,贪心地想,肯定是只用收益最大的跳跃,才能使得回滚次数最少,那么就按净收益排序,选最大的计算即可。

三、C1. XOR Convenience (Easy Version)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF=1e9;
const ll INFLL=1e18;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

void solve()
{
    int n;
    cin>>n;

    set<int>st;
    for(int i=2;i<=n;i++)
    {
        st.insert(i);
    }

    vector<int>ans(n+1);
    ans[n]=1;
    for(int i=2;i<=n-1;i++)
    {
        ans[i]=ans[n]^i;
        st.erase(ans[i]);
    }

    ans[1]=*st.begin();

    for(int i=1;i<=n;i++)
    {
        cout<<ans[i]<<" ";
    }
    cout<<endl;
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

C1就是只需要考虑 i 的范围不包括1位置时的构造方法。因为唯一没有限制可以随便填的就是最后一个位置,且每个位置都和后缀位置的数有关,所以优先考虑从最后位置开始填。那么一个自然的想法就是可以让前面的每个数字的 j 都等于最后位置,那么其实可以考虑给最后位置填1,这样前面每个位置异或1都是两两一对的了。最后,只需要把没出现的补到1位置即可。

四、C2. XOR-convenience (Hard Version)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF=1e9;
const ll INFLL=1e18;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

void brute()
{
    int n=12;
    vector<int>p(n+1);
    for(int i=1;i<=n;i++)
    {
        p[i]=i;
    }

    vector<vector<int>>ans;
    do
    {
        bool br=false;
        for(int i=n-1;i>=1;i--)
        {
            bool flag=false;
            for(int j=i;j<=n;j++)
            {
                if(p[i]==(p[j]^i))
                {
                    flag=true;
                    break;
                }
            }
            if(!flag)
            {
                br=true;
                break;
            }
        }
        if(!br)
        {
            ans.push_back(p);
        }

    }while(next_permutation(p.begin()+1,p.end()));

    if(ans.size())
    {
        cout<<ans.size()<<endl;
        for(auto &vec:ans)
        {
            if(vec[n]!=1)
            {
                continue;
            }
            for(int i=1;i<=n;i++)
            {
                cout<<vec[i]<<" ";
            }
            cout<<endl;
        }
    }
    else
    {
        cout<<-1<<endl;
    }
}

void solve()
{
    int n;
    cin>>n;

    int d=0;
    while((1ll<<d)<n)
    {
        d++;
    }

    if((1ll<<d)==n)
    {
        cout<<-1<<endl;
        return ;
    }

    set<int>st;
    for(int i=2;i<=n;i++)
    {
        st.insert(i);
    }

    vector<int>ans(n+1);
    ans[n]=1;
    for(int i=2;i<=n-1;i++)
    {
        ans[i]=ans[n]^i;
        st.erase(ans[i]);
    }

    ans[1]=*st.begin();

    if(n%2==0)
    {
        int lowbit=n&-n;

        swap(ans[1],ans[lowbit]);
    }

    for(int i=1;i<=n;i++)
    {
        cout<<ans[i]<<" ";
    }
    cout<<endl;
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

C2就比较困难了。

若加上1位置的限制,首先注意到奇数长度时,因为每个位置上的数都是异或最后一位的1得来的,而 n 这个数因为是奇数所以第0位必然是1。所以,在之前构造的过程中,n 这个数一定会被填过。那么不管1位置填什么,异或1后+1或者-1的结果都是小于等于n的,那么就维持不变就可以了。

而当是偶数长度时,因为第0位是0,那么在前面构造的过程中必然不可能存在一个数异或上1的结果是 n。那么,第1个位置补的时候就必然会补成 n,那么后续就必然不存在一个数使得其异或1的结果是 n。此时就可以考虑把1位置的数和某个位置交换一下,从而使得整个构造合法。

回顾不合法的原因,是因为偶数不存在第0位的1,异或1必然导致+1,所以后续不存在一个数异或1的结果是 n。那么其实可以考虑去找一个是1的位,让其异或这个位后把这位上的1消去即可。所以,就可以去找 n 的 lowbit,然后交换1位置和 lowbit 位置的数。首先,容易证明交换到1位置的数在后续必然是存在的,那么就只需要证明把 n 交换到 lowbit 位置是合法的。因为要求后续存在一个位置 j 上的数 x,使得这个数等于 n 异或 lowbit。而又因为这个 x 是由 j 异或最后的1得到的,那么 n 在去掉 lowbit 后的这个数必然大于 lowbit,所以不管异或是+1还是-1,位置 j 必然在位置 lowbit 之后,所以这个方法是可行的。

五、D1. Little String (Easy Version)

太难了......

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF=1e9;
const ll INFLL=1e18;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

template<class T>
constexpr T power(T a, ll b) {
    T res = 1;
    for (; b != 0; b /= 2, a *= a) {
        if (b & 1) {
            res *= a;
        }
    }
    return res;
}

template<int M>
struct ModInt {
public:
    constexpr ModInt() : x(0) {}

    template<typename T>
    constexpr ModInt(T x_) {
        T v = x_ % M;
        if (v < 0) {
            v += M;
        }
        x = v;
    }
 
    constexpr int val() const {
        return x;
    }
 
    constexpr ModInt operator-() const {
        ModInt res;
        res.x = (x == 0 ? 0 : M - x);
        return res;
    }
 
    constexpr ModInt inv() const {
        return power(*this, M - 2);
    }
 
    constexpr ModInt &operator*=(const ModInt &rhs) &{
        x = ll(x) * rhs.val() % M;
        return *this;
    }
 
    constexpr ModInt &operator+=(const ModInt &rhs) &{
        x += rhs.val();
        if (x >= M) {
            x -= M;
        }
        return *this;
    }
 
    constexpr ModInt &operator-=(const ModInt &rhs) &{
        x -= rhs.val();
        if (x < 0) {
            x += M;
        }
        return *this;
    }
 
    constexpr ModInt &operator/=(const ModInt &rhs) &{
        return *this *= rhs.inv();
    }
 
    friend constexpr ModInt operator*(ModInt lhs, const ModInt &rhs) {
        lhs *= rhs;
        return lhs;
    }
 
    friend constexpr ModInt operator+(ModInt lhs, const ModInt &rhs) {
        lhs += rhs;
        return lhs;
    }
 
    friend constexpr ModInt operator-(ModInt lhs, const ModInt &rhs) {
        lhs -= rhs;
        return lhs;
    }
 
    friend constexpr ModInt operator/(ModInt lhs, const ModInt &rhs) {
        lhs /= rhs;
        return lhs;
    }
 
    friend constexpr bool operator==(ModInt lhs, const ModInt &rhs) {
        return lhs.val() == rhs.val();
    }
    
    friend constexpr bool operator<(ModInt lhs, const ModInt &rhs) {
        return lhs.val() < rhs.val();
    }
    
    friend constexpr bool operator>(ModInt lhs, const ModInt &rhs) {
        return lhs.val() > rhs.val();
    }
    
    friend constexpr bool operator<=(ModInt lhs, const ModInt &rhs) {
        return lhs.val() <= rhs.val();
    }
    
    friend constexpr bool operator>=(ModInt lhs, const ModInt &rhs) {
        return lhs.val() >= rhs.val();
    }
    
    friend constexpr bool operator!=(ModInt lhs, const ModInt &rhs) {
        return lhs.val() != rhs.val();
    }
 
    friend constexpr std::istream &operator>>(std::istream &is, ModInt &a) {
        ll i;
        is >> i;
        a = i;
        return is;
    }
 
    friend constexpr std::ostream &operator<<(std::ostream &os, const ModInt &a) {
        return os << a.val();
    }
 
private:
    int x;
};

template<int M, typename T = ModInt<M>>
struct Comb {
    vector<T> fac;
    vector<T> inv;
 
    Comb(int n) {
        fac.assign(n, 1);
        for(int i=1;i<n;i++)
        {
            fac[i]=fac[i-1]*i;
        }
        inv.assign(n, 1);
        inv[n-1]=fac[n-1].inv();
        for(int i=n-2;i>=0;i--)
        {
            inv[i]=inv[i+1]*(i+1);
        }
    }
 
    template<std::signed_integral U>
    T P(U n, U m) {
        if(n<m)
        {
            return 0;
        }
        return fac[n] * inv[n - m];
    }
 
    template<std::signed_integral U>
    T C(U n, U m) {
        if(n<m||m<0)
        {
            return 0;
        }
        return fac[n] * inv[n - m] * inv[m];
    }
};
 
constexpr int M = 1e9+7;
using Z = ModInt<M>;

void solve()
{
    ll n,c;
    cin>>n>>c;
    string s;
    cin>>s;
    s=" "+s;

    if(s[1]=='0'||s[n]=='0')
    {
        cout<<-1<<endl;
        return ;
    }

    Z ans=1;
    for(ll i=1;i<=n-1;i++)
    {
        if(s[i]=='0')
        {
            c/=__gcd(c,i-1);
            ans*=(i-1);
        }
        else
        {
            c/=__gcd(c,2ll);
            ans*=2;
        }
    }

    if(c==1)
    {
        cout<<-1<<endl;
    }
    else
    {
        cout<<ans<<endl;
    }
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

首先,可以考虑哪些排列 p 满足字符串 w 的限制。那么可以发现,若 w[1]=0 或 w[n]=0 ,那么必然不可能存在合法的排列。因为只需要区间是0这个数字本身、区间是排列整体就可以使 MEX 不符合条件。所以可以考虑假设 w[1]=w[n]=1, 然后从0开始,往排列里插入数字。

对于当前来到的数字 k,此时 0~k-1 的数字已经排好了,那么就有 k+1 种插入方式。首先,考虑插入到开头或结尾的情况。那么就必然可以通过选择剩下的所有数字,使得 MEX 等于 k,即使之后再往中间插入的话也不会影响 MEX 了。之后,考虑插入到中间的情况。此时,因为 k 的左右两侧就都是小于 k 的数,又因为如果想让 MEX 等于 k 的话,就必须把所有小于 k 的数都包含,那么就必然会导致把 k 选入,所以此时的 MEX 是不可能等于 k 的。所以,若 w[i]=1,那么就有放头尾的两种选择;若 w[i]=0,那么就有 i-1 种选择。所以就有公式:

因为在D1中 w 就是 s 本身,所以只需要检查 f(s) 是否能被 c 整除即可。那么就只需要遍历所有的 i,然后让 c 除以和当前乘数的 gcd。若最终 c=1,那么就说明无答案,否则就输出即可。

六、D2. Little String (Hard Version)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF=1e9;
const ll INFLL=1e18;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

template<class T>
constexpr T power(T a, ll b) {
    T res = 1;
    for (; b != 0; b /= 2, a *= a) {
        if (b & 1) {
            res *= a;
        }
    }
    return res;
}

template<int M>
struct ModInt {
public:
    constexpr ModInt() : x(0) {}

    template<typename T>
    constexpr ModInt(T x_) {
        T v = x_ % M;
        if (v < 0) {
            v += M;
        }
        x = v;
    }
 
    constexpr int val() const {
        return x;
    }
 
    constexpr ModInt operator-() const {
        ModInt res;
        res.x = (x == 0 ? 0 : M - x);
        return res;
    }
 
    constexpr ModInt inv() const {
        return power(*this, M - 2);
    }
 
    constexpr ModInt &operator*=(const ModInt &rhs) &{
        x = ll(x) * rhs.val() % M;
        return *this;
    }
 
    constexpr ModInt &operator+=(const ModInt &rhs) &{
        x += rhs.val();
        if (x >= M) {
            x -= M;
        }
        return *this;
    }
 
    constexpr ModInt &operator-=(const ModInt &rhs) &{
        x -= rhs.val();
        if (x < 0) {
            x += M;
        }
        return *this;
    }
 
    constexpr ModInt &operator/=(const ModInt &rhs) &{
        return *this *= rhs.inv();
    }
 
    friend constexpr ModInt operator*(ModInt lhs, const ModInt &rhs) {
        lhs *= rhs;
        return lhs;
    }
 
    friend constexpr ModInt operator+(ModInt lhs, const ModInt &rhs) {
        lhs += rhs;
        return lhs;
    }
 
    friend constexpr ModInt operator-(ModInt lhs, const ModInt &rhs) {
        lhs -= rhs;
        return lhs;
    }
 
    friend constexpr ModInt operator/(ModInt lhs, const ModInt &rhs) {
        lhs /= rhs;
        return lhs;
    }
 
    friend constexpr bool operator==(ModInt lhs, const ModInt &rhs) {
        return lhs.val() == rhs.val();
    }
    
    friend constexpr bool operator<(ModInt lhs, const ModInt &rhs) {
        return lhs.val() < rhs.val();
    }
    
    friend constexpr bool operator>(ModInt lhs, const ModInt &rhs) {
        return lhs.val() > rhs.val();
    }
    
    friend constexpr bool operator<=(ModInt lhs, const ModInt &rhs) {
        return lhs.val() <= rhs.val();
    }
    
    friend constexpr bool operator>=(ModInt lhs, const ModInt &rhs) {
        return lhs.val() >= rhs.val();
    }
    
    friend constexpr bool operator!=(ModInt lhs, const ModInt &rhs) {
        return lhs.val() != rhs.val();
    }
 
    friend constexpr std::istream &operator>>(std::istream &is, ModInt &a) {
        ll i;
        is >> i;
        a = i;
        return is;
    }
 
    friend constexpr std::ostream &operator<<(std::ostream &os, const ModInt &a) {
        return os << a.val();
    }
 
private:
    int x;
};

template<int M, typename T = ModInt<M>>
struct Comb {
    vector<T> fac;
    vector<T> inv;
 
    Comb(int n) {
        fac.assign(n, 1);
        for(int i=1;i<n;i++)
        {
            fac[i]=fac[i-1]*i;
        }
        inv.assign(n, 1);
        inv[n-1]=fac[n-1].inv();
        for(int i=n-2;i>=0;i--)
        {
            inv[i]=inv[i+1]*(i+1);
        }
    }
 
    template<std::signed_integral U>
    T P(U n, U m) {
        if(n<m)
        {
            return 0;
        }
        return fac[n] * inv[n - m];
    }
 
    template<std::signed_integral U>
    T C(U n, U m) {
        if(n<m||m<0)
        {
            return 0;
        }
        return fac[n] * inv[n - m] * inv[m];
    }
};
 
constexpr int M = 1e9+7;
using Z = ModInt<M>;

void solve()
{
    ll n,c;
    cin>>n>>c;
    string s;
    cin>>s;
    s=" "+s;
    
    if(s[2]=='?')
    {
        s[2]='0';
    }
    if(s[1]=='0'||s[n]=='0')
    {
        cout<<-1<<endl;
        return ;
    }

    s[1]='1',s[n]='1';

    vector<int>odd;
    int cnt=0;
    for(ll i=1;i<=n-1;i++)
    {
        if(s[i]=='0')
        {
            c/=__gcd(c,i-1);
        }
        else if(s[i]=='1')
        {
            c/=__gcd(c,2ll);
        }
        else
        {
            cnt++;
            if((i-1)%2==1)
            {
                odd.push_back(i);
            }
        }
    }

    //不是2的幂
    if(c!=(1ll<<__lg(c)))
    {
        Z ans=1;
        for(int i=1;i<=n-1;i++)
        {
            if(s[i]=='0')
            {
                ans*=(i-1);
            }
            else 
            {
                ans*=2;
            }
        }
        cout<<ans<<endl;
        return ;
    }   

    //是2的幂

    //剩下的问号个数
    int rest=cnt;
    int d=__lg(c);
    for(auto x:odd)
    {
        //剩下的全选2都不会超
        if(rest<d)
        {
            break;
        }

        //不选2
        s[x]='0';
        rest--;
    }

    //偶数的个数大于等于d -> 无解
    if(rest>=d)
    {
        cout<<-1<<endl;
        return ;
    }

    Z ans=1;
    for(int i=1;i<=n-1;i++)
    {
        if(s[i]=='0')
        {
            ans*=(i-1);
        }
        else
        {
            ans*=2;
        }
    }
    cout<<ans<<endl;
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

因为对于 s 中0或1的部分的贡献已经确定,这部分记为 b。而对于 s 中因为是?而没确定的部分,这部分记为 x。那么问题就变成了找到最小的 x,使得 bx 不能被 c 整除,bx 可以表示为:

因为 b 已经固定,所以可以消去 b ,那么就要求 x 不能被 整除。那么首先,因为 s[1] 和 s[n] 都要求是1,那么从 s[2] 开始考虑。如果 s[2] 是?,那么肯定是考虑让其等于0,因为此时乘以1不会对是否能被整除造成影响。之后,问题就变为了,需要选择若干个 ,让 x 乘以2或 j,使得乘积最小且不能被整除。

之后考虑分类讨论,首先,若 c' 是2的幂,那么对于所有的偶数 j,考虑都选择将其乘以2,因为这样可以使得乘积最小。之后,对于剩下的奇数 j,考虑贪心地选择尽可能多的2,使得乘积最小且不能被 c' 整除。而若 c' 不是2的幂,那么就可以每次都乘2,这样可以保证 x 不能被 c' 整除,且乘积是最小的。

总结

数论还是太难......

END

相关推荐
添砖java‘’2 小时前
线程的互斥与同步
linux·c++·操作系统·线程·信息与通信
2401_838472512 小时前
C++模拟器开发实践
开发语言·c++·算法
3108748762 小时前
0005.C/C++学习笔记5
c语言·c++·学习
s1hiyu2 小时前
实时控制系统验证
开发语言·c++·算法
daad7772 小时前
V4L2_mipi-csi
算法
楼田莉子2 小时前
C++现代特性学习:C++14
开发语言·c++·学习·visual studio
2301_765703143 小时前
C++代码复杂度控制
开发语言·c++·算法
m0_708830963 小时前
C++中的享元模式实战
开发语言·c++·算法
naruto_lnq3 小时前
分布式计算C++库
开发语言·c++·算法