2016CCPC杭州站部分简要题解

最近状态不行,这套题没有1个是1A的。。。。

A - ArcSoft's Office Rearrangement

从左往右扫一遍,如果当前的和超过平均值,就可以生成平均数。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int a[maxn] ;
int main()
{
    ios ;
    int T ;
    cin >> T ;
    rep(cas , 1 , T)
    {
        cout << "Case #" << cas << ": " ;
        int n , k ;
        cin >> n >> k ;
        ll sum = 0 ;
        rep(i , 1 , n)  cin >> a[i] , sum += a[i] ;
        if(sum % k != 0)  cout << -1 << '\n' ;
        else
        {
            sum /= k ;
            ll ans = 0 ;
            ll res = 0 ;
            rep(i , 1 , n)
            {
                if(res > 0)  ans ++ ;
                res += a[i] ;
                if(res % sum == 0)  ans += res / sum - 1 , res = 0 ;
                else  ans += res / sum , res %= sum ;
            }
            cout << ans << '\n' ;
        }
    }
    return 0 ;
}

B - Bomb

如果引爆炸弹\dpi{150}i可以使炸弹j爆炸,那么连接一条\dpi{150}i指向j的有向边。然后缩点,每个强联通分量的权值就是里面的点的权值的最小值。对于缩点后的图,累加入度为0的点的权值即可。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 1e3 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int n ;
int x[maxn] , y[maxn] , r[maxn] ;
int c[maxn] ;
struct Link
{
    int num , head[maxn] ;
    struct Edge
    {
        int v , next ;
    } edge[maxn * maxn] ;
    void init()
    {
        num = 0 ;
        memset(head , -1 , sizeof(head)) ;
    }
    void add_edge(int u , int v)
    {
        edge[num].v = v ;
        edge[num].next = head[u] ;
        head[u] = num ++ ;  
    } 
} link ;
struct Tarjan
{
    int cnt , scc_num , lay ;
    int low[maxn] , dfn[maxn] , belong[maxn] ; 
    int st[maxn] , s[maxn] ;
    int mn[maxn] ;
    int in[maxn] ;
    bool vis[maxn] ;
    void init()
    {
        cnt = scc_num = lay = 0 ;
        memset(vis , 0 , sizeof(vis)) ;
        memset(low , 0 , sizeof(low)) ;
        memset(dfn , 0 , sizeof(dfn)) ;
        mem_inf(mn) ;
        mem0(in) ;
    }
    void dfs(int k)
    {
        vis[k] = 1 ;
        low[k] = dfn[k] = ++ lay ;
        st[++ cnt] = k ;
        for(int i = link.head[k] ; i != -1 ; i = link.edge[i].next)
        {
            int v = link.edge[i].v ;
            if(dfn[v] == 0)
            {
                dfs(v) ;
                low[k] = min(low[k] , low[v]) ;
            }
            else if(vis[v])
            low[k] = min(low[k] , dfn[v]) ;
        }
        if(dfn[k] == low[k])
        {
            ++ scc_num ;
            do
            {
                belong[st[cnt]] = scc_num ;
                vis[st[cnt]] = 0 ;
                cnt -- ;
            } while(st[cnt + 1] != k) ;
        }
    }
    void cal()
    {
        for(int i = 1 ; i <= n ; i ++)
        if(dfn[i] == 0)  dfs(i) ;
    }
    void solve(int cas)
    {
        cout << "Case #" << cas << ": " ;
        int ans = 0 ;
        rep(i , 1 , n)  mn[belong[i]] = min(mn[belong[i]] , c[i]) ;
        rep(i , 1 , n)  for(int j = link.head[i] ; j != -1 ; j = link.edge[j].next)
        {
            int v = link.edge[j].v ;
            if(belong[i] == belong[v])  continue ;
            else  in[belong[v]] ++ ;
        }
        rep(i , 1 , scc_num)  if(in[i] == 0)  ans += mn[i] ;
        cout << ans << '\n' ;
    }
} tarjan ; 
bool ok(int i , int j)
{
    ll d = 1ll * (x[i] - x[j]) * (x[i] - x[j]) + 1ll * (y[i] - y[j]) * (y[i] - y[j]) ;
    return 1ll * r[i] * r[i] >= d ;
}
int main()
{
    ios ;
    int T ;
    cin >> T ;
    rep(cas , 1 , T)
    {
        cin >> n ;
        rep(i , 1 , n)  cin >> x[i] >> y[i] >> r[i] >> c[i] ;
        link.init() ;
        tarjan.init() ;
        rep(i , 1 , n)  rep(j , 1 , n)  if(ok(i , j))  link.add_edge(i , j) ;
        tarjan.cal() ;
        tarjan.solve(cas) ;
    }
    return 0 ;
}

 C - Car

最后一段用时1秒,倒着推就行了。速度可以是实数。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int n , a[maxn] ;
int main()
{
    ios ;
    int T ;
    cin >> T ;
    rep(cas , 1 , T)
    {
        cin >> n ;
        rep(i , 1 , n)  cin >> a[i] ;
        cout << "Case #" << cas << ": " ;
        ll ans = 1 ;
        db v = a[n] - a[n - 1] ;
        per(i , n - 1 , 1)
        {
            int d = a[i] - a[i - 1] ;
            int t = (d + v - eps) / v ;
            v = (db)d / t ;
            ans += t ;
        }
        cout << ans << '\n' ;
    }
    return 0 ;
}

D - Difference

先猜个很对的结论,y最多是10位数。这个结论一看就很对,不过不会证。

然后你爆搜肯定是T的,折半一下就好了。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
ll x , k ;
ll r[15][15] ;
int sum[maxn][15] ;
unordered_map<ll , int> cnt[15] ;
void init()
{
    rep(i , 1 , 9)  rep(j , 1 , 9)
    {
        ll res = 1 ;
        rep(k , 1 , j)  res *= i ;
        r[i][j] = res ;
    }
    int mx = 0 ;
    rep(s , 0 , 99999)  rep(k , 1 , 9)
    {
        ll tmp = s ;
        ll res = 0 ;
        while(tmp > 0)  res += r[tmp % 10][k] , tmp /= 10 ;
        sum[s][k] = res ;
        if(cnt[k].count(res - s))  cnt[k][res - s] ++ ;
        else  cnt[k][res - s] = 1 ;
    }
}
ll solve(ll s)
{
    ll res = sum[s][k] ;
    res -= s * 100000 ;
    res = x - res ;
    if(cnt[k].count(res))  return cnt[k][res] ;
    else  return 0 ;
}
void print(int cas)
{
    cout << "Case #" << cas << ": " ;
}
int main()
{
    ios ;
    int T ;
    init() ;
    cin >> T ;
    rep(cas , 1 , T)
    {
        cin >> x >> k ;
        ll ans = 0 ;
        rep(i , 0 , 99999)  ans += solve(i) ;
        print(cas) ;
        cout << ans - (x == 0) << '\n' ;
    }
    return 0 ;
}

 E - Equation

满足条件的式子最多有36个。爆搜剪枝即可。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int num[maxn] ;
int ans ;
vector<array<int , 3> > v ;
void print(int cas)
{
    cout << "Case #" << cas << ": " ;
}
void dfs(int now , int res)
{
    if(now == sz(v))
    {
        ans = max(ans , res) ;
        return ;
    }
    if(sz(v) - now + res <= ans)  return ;
    //不取
    dfs(now + 1 , res) ;

    //取
    int i = v[now][0] , j = v[now][1] , k = v[now][2] ;
    if(num[i] == 0 || num[j] == 0 || num[k] == 0)  return ;
    if(i == j && num[i] < 2)  return ;
    num[i] -- , num[j] -- , num[k] -- ;
    dfs(now + 1 , res + 1) ;
    num[i] ++ , num[j] ++ , num[k] ++ ;
}
int main()
{
    ios ;
    int T ;
    rep(i , 1 , 9)  rep(j , 1 , 9)  rep(k , 1 , 9)  if(i + j == k)  v.pb({i , j , k}) ;
    cin >> T ;
    rep(cas , 1 , T)
    {
        rep(i , 1 , 9)  cin >> num[i] ;
        print(cas) ;
        ans = 0 ;
        dfs(0 , 0) ;
        cout << ans << '\n' ;
    }
    return 0 ;
}

F - Four Operations

 还是得猜个结论。对于a+b-c*d/ec,d都是1位数,e1位数或者2位数。然后分类讨论就行了。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
int len ; 
char s[maxn] ;
void print(int cas)
{
    cout << "Case #" << cas << ": " ;
}
ll solve1()
{
    ll sum = s[1] - '0' ;
    ll res = 0 ;
    rep(i , 2 , len - 3)  res = res * 10 + (s[i] - '0') ;
    sum += res ;
    sum -= (s[len - 2] - '0') * (s[len - 1] - '0') / (s[len] - '0') ;
    return sum ;
}
ll solve2()
{
    ll sum = s[len - 3] - '0' ;
    ll res = 0 ;
    rep(i , 1 , len - 4)  res = res * 10 + (s[i] - '0') ;
    sum += res ;
    sum -= (s[len - 2] - '0') * (s[len - 1] - '0') / (s[len] - '0') ;
    return sum ;
}
ll solve3()
{
    if(len == 5)  return -1e18 ;
    ll sum = s[len - 4] - '0' ;
    ll res = 0 ;
    rep(i , 1 , len - 5)  res = res * 10 + (s[i] - '0') ;
    sum += res ;
    sum -= (s[len - 3] - '0') * (s[len - 2] - '0') / ((s[len - 1] - '0') * 10 + (s[len] - '0')) ;
    return sum ;
}
ll solve4()
{
    if(len == 5)  return -1e18 ;
    ll sum = s[1] - '0' ;
    ll res = 0 ;
    rep(i , 2 , len - 4)  res = res * 10 + (s[i] - '0') ;
    sum += res ;
    sum -= (s[len - 3] - '0') * (s[len - 2] - '0') / ((s[len - 1] - '0') * 10 + (s[len] - '0')) ;
    return sum ;
}
int main()
{
    ios ;
    int T ;
    cin >> T ;
    rep(cas , 1 , T)
    {
        cin >> s + 1 ;
        len = strlen(s + 1) ;
        print(cas) ;
        cout << max({solve1() , solve2() , solve3() , solve4()}) << '\n' ;
    }
    return 0 ;
}

I - Inequality

这个dp很神。有一个显然的结论:最优解是由若干个长度不小于2的段拼接而成。

如果一个连续段全部取等号,那么设段内首项是x,那么就是最小化a*x+\frac{b}{x}。因为第一项确定了,后面每一项都确定了。

dp[i][j]表示x[1...j]符合要求且x[i...j]全部取等号的最小代价。

主要的是怎么将2个段拼接成1个段。

x[j...i],x[i+1...k]拼接成x[j...k],也就是最小化dp[i+1][k]。其中x[j...i]由多个长度不小于2的段拼接而成,x[i+1...k]由单个长度不小于2的段拼接而成。

此时只要对于x[i+1...k]寻找满足x_{i}*x_{i+1} \geqslant a_i最小的dp[j][i]即可。枚举i,k,其他的部分可以预处理然后二分查找。

时间复杂度:O(n^2 * log(n))

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef double db ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef pair<db , db> pdd ;
const int mod = 998244353 ;
const int maxn = 3000 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int n ;
db c[maxn] ;
db val[maxn][maxn] ;
db lx[maxn][maxn] , rx[maxn][maxn] ;
db dp[maxn][maxn] ;
db oe , eo ;
db mn[maxn] ;
void print(int cas)
{
    cout << "Case #" << cas << ": " ;
}
void add(int i , int j)
{
    if((j - i + 1) % 2 == 0)  oe /= c[j] , eo *= c[j] ;
    else  oe *= c[j] , eo /= c[j] ;
}
db cal(int i , int j)
{
    if((j - i + 1) % 2 == 0)  return eo ;
    else  return oe ;
    // if(j % 2 == 0)  return (e[j] / e[i - 1]) / (o[j] / o[i - 1]) ;
    // else  return (o[j] / o[i - 1]) / (e[j] / e[i - 1]) ;
}
void init()
{
    rep(i , 1 , n)  
    {
        db a = 1 , b = 0 ;
        db cur = 1 ;
        oe = 1 ;
        eo = 1 ;
        rep(j , i + 1 , n)
        {
            cur = c[j - 1] / cur ;
            add(i , j - 1) ;
            if((j - i + 1) % 2 == 0)  b += cur ;
            else  a += cur ;
            val[i][j] = 2.0 * sqrt(a * b) ;
            lx[i][j] = sqrt(b / a) ;
            rx[i][j] = cal(i , j - 1) ;
            if((j - i + 1) % 2 == 0)  rx[i][j] /= lx[i][j] ;
            else  rx[i][j] *= lx[i][j] ;
            //cout << fixed << setprecision(5) << rx[i][j] << '\n' ;
        }
    }
}
void solve()
{
    rep(i , 1 , n)  rep(j , i , n)  dp[i][j] = 1e10 ;
    rep(i , 1 , n)  dp[1][i] = val[1][i] ;
    rep(i , 2 , n - 1)
    {
        vector<pdd> v ;
        rep(j , 1 , n)  mn[j] = 1e10 ;
        v.pb({0 , 0}) ;
        rep(j , 1 , i - 1)  v.pb({rx[j][i] , dp[j][i]}) ;
        sort(all(v)) ;
        mn[i] = 1e10 ;
        per(j , i - 1 , 1)  mn[j] = min(mn[j + 1] , v[j].se) ;  
        rep(k , i + 2 , n)
        {
            int p = lower_bound(all(v) , pdd{c[i] / lx[i + 1][k] - 1e-8 , 0.0}) - v.begin() ;
            if(p == sz(v))  continue ;
            dp[i + 1][k] = val[i + 1][k] + mn[p] ;
        }
    }
}
int main()
{
    ios ;
    int T ;
    cin >> T ;
    rep(cas , 1 , T)
    {
        cin >> n ;
        rep(i , 1 , n - 1)  cin >> c[i] ;
        init() ;
        solve() ;
        print(cas) ;
        db ans = 1e10 ;
        rep(i , 1 , n)   ans = min(ans , dp[i][n]) ;
        cout << fixed << setprecision(5) << ans << '\n' ;
    }
    return 0 ;
}

J - Just a Math Problem

有两种做法。

这题很卡常。

对于S(n),当n比较小时需要记忆化。

时间复杂度:O(sqrt(n)*log(n))

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 1e9 + 7 ;
const int maxn = 1e6 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
ll n ;
void print(int cas)
{
    cout << "Case #" << cas << ": " ;
}
bool vis[maxn] ;
int prime[maxn] ;
int mu[maxn] ;
int cnt = 0 ;
ll S[maxn] ;
void get_mu(int n)
{
   mu[1] = 1 ;
   mem0(vis) ;
   for(int i = 2 ; i <= n ; i ++)
   {
     if(!vis[i])  prime[++ cnt] = i , mu[i] = -1 ;
     for(int j = 1 ; j <= cnt && prime[j] * i <= n ; j ++)
     {
       vis[prime[j] * i] = 1 ;
       if(i % prime[j] == 0)  break ;
        else  mu[i * prime[j]] = -mu[i] ;
     }
   }
}
ll cal(ll n)
{
   if(n <= 1000000 && S[n])  return S[n] ;  
   ll ans = 0 ;
   for(ll l = 1 , r ; l <= n ; l = r + 1)
   {
     r = n / (n / l) ;
     ans += ll(r - l + 1) * (n / l) ;
   }
   ans %= mod ;
   if(n <= 1000000)  S[n] = ans ;
   return ans ;
}
int main()
{
    ios ;
    int T ;
    get_mu(1000000) ;
    cin >> T ;
    rep(cas , 1 , T)
    {
        cin >> n ;
        print(cas) ;
        ll ans = 0 ;
        for(int k = 1 ; k <= n / k ; k ++)
        {
            if(mu[k] == 0)  continue ;
            ans += mu[k] * cal(n / (1ll * k * k)) % mod ;
            ans %= mod ;
        }
        cout << (ans + mod) % mod << '\n' ;
    }
    return 0 ;
}

K - Kingdom of Obsession

本质是两个区间[1,n],[s+1,s+n]的匹配。但是直接做肯定不行,首先两个相交部分直接匹配就行了,不会使匹配结果更劣。

然后去掉相交的部分,变成了[l_1,r_1],[l_2,r_2]。如果[l2,r2]内部有2个素数,那就无解。所以区间长度不超过300。跑一遍HK就行了。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int n , m ;
int l1 , r1 , l2 , r2 ;
struct HK //求二分图最大匹配数
{
    //复杂度 O(sqrt(n)*m),n是点数,m是边数
    vector<int> G[maxn] ; //单向边,左边->右边
    int uN ;// uN 为左端的顶点数,使用前赋值 (点编号 0 开始)
    int Mx[maxn] , My[maxn] ;
    int dx[maxn] , dy[maxn] ;
    int dis ;
    bool used[maxn] ;
    void init()
    {
        //确定uN大小 
        n = r1 - l1 + 1 ;
        uN = n ;
        rep(i , 0 , uN - 1)  cl(G[i]) ;
    }
    void draw() //存储二分图G[]
    {
        rep(i , 0 , uN - 1)  rep(j , 0 , uN - 1)
        {
            int x = i + l1 ;
            int y = j + l2 ;
            if(y % x == 0)  G[i].pb(j) ;
        }
    }
    bool SearchP()
    {
        queue<int> Q ;
        dis = inf ;
        rep(i , 0 , uN - 1)  dx[i] = dy[i] = -1 ;
        rep(i , 0 , uN - 1)  if(Mx[i] == -1)  Q.push(i) , dx[i] = 0 ;
        while(!Q.empty())
        {
            int u = Q.front() ;
            Q.pop() ;
            if(dx[u] > dis)  break ;
            int sz = G[u].size() ;
            rep(i , 0 , sz - 1)
            {
                int v = G[u][i] ;
                if(dy[v] == -1)
                {
                    dy[v] = dx[u] + 1 ;
                    if(My[v] == -1)  dis = dy[v] ;
                    else
                    {
                        dx[My[v]] = dy[v] + 1 ;
                        Q.push(My[v]) ;
                    }
                }
            }
        }
        return dis != inf ;
    }
    bool dfs(int u)
    {
        for(auto v : G[u])
        {
            if(!used[v] && dy[v] == dx[u] + 1)
            {
                used[v] = true ;
                if(My[v] != -1 && dy[v] == dis)  continue ;
                if(My[v] == -1 || dfs(My[v]))
                {
                    My[v] = u ;
                    Mx[u] = v ;
                    return true ;
                }
            }
        }
        return false ;
    }
    int MaxMatch()
    {
        int res = 0 ;
        rep(i , 0 , uN - 1)  Mx[i] = My[i] = -1 ;
        while(SearchP())
        {
            rep(i , 0 , uN - 1)  used[i] = 0 ;
            rep(i , 0 , uN - 1)  
            {
                if(Mx[i] == -1 && dfs(i))  res ++ ;
            }
        }
        return res ;
    }
    void solve(int cas)
    {
        cout << "Case #" << cas << ": " ;
        if(MaxMatch() == n)  cout << "Yes\n" ;
        else  cout << "No\n" ;
    }
} hk ;
void win(int cas)
{
    cout << "Case #" << cas << ": " ;
    cout << "Yes\n" ;
}
void lose(int cas)
{
    cout << "Case #" << cas << ": " ;
    cout << "No\n" ;
}
int main()
{
    ios ;
    int T ;
    cin >> T ;
    rep(cas , 1 , T)
    {
        int n , s ;
        cin >> n >> s ;
        if(s == 0)
        {
            win(cas) ;
            continue ;
        }
        l1 = 1 , r1 = n ;
        l2 = s + 1 , r2 = s + n ;
        if(l2 <= r1)
        {
            int tmp1 = l2 - 1 ;
            int tmp2 = r1 + 1 ;
            r1 = tmp1 ;
            l2 = tmp2 ;
        }
        if(r1 - l1 > 300)
        {
            lose(cas) ;
            continue ;
        }
        hk.init() ;
        hk.draw() ;
        hk.solve(cas) ;
    }
    return 0 ;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值