Problem B: 故障电灯(light)

Posted luoyibujue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Problem B: 故障电灯(light)相关的知识,希望对你有一定的参考价值。

  • 考虑对电灯进行差分:若第i个电灯和第i + 1个电灯状态不同,则在第i个位置上放一个球
    这样我们就放置了不超过2n个球,且必然是偶数个
    于是问题转化为:有m个球,每一步可以把一个球平移奇质数个位置,两个球位于相同位置则同时被消除,计算至
    少多少步能消除所有球
  • 然后我们发现, 假如两个东西距离为奇质数cost为1, 偶数cost为二(哥德巴赫猜想), 其余奇数的话cost为3
  • 然后发现一种贪心方法, 是尽量匹配cost为1的, 然后分奇偶性各自用2覆盖,看看最后剩下的那个直接判断即可
#include<cstdio> 
#include<algorithm> 
#include<cstring> 
#include<queue> 
#include<iostream> 
#define ll long long
#define mmp make_pair
#define M
using namespace std; 
int read() {
    int nm = 0, f = 1;
    char c = getchar();
    for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
    return nm * f;
}
struct Edge{
    int v, c, nxt; 
}e[200010]; 
int head[10010], tot = 1; 
void build(int u, int v, int c)
{
    e[++tot] = (Edge){v, c, head[u]}; 
    head[u] = tot; 
    return ; 
}
void insert(int u, int v, int c)
{
    build(u, v, c); 
    build(v, u, 0); 
    return ; 
}
int dep[10010]; 
int S, T; 
queue<int> q; 
bool bfs()
{
    memset(dep, 0, sizeof(dep)); 
    dep[S] = 1; 
    q.push(S); 
    while(!q.empty())
    {
        int u = q.front(); 
        q.pop(); 
        for(int i = head[u]; i; i = e[i].nxt)
            if(!dep[e[i].v]&&e[i].c)
            {
                dep[e[i].v] = dep[u] + 1; 
                q.push(e[i].v); 
            }
    }
    if(dep[T])return true; 
    return false; 
}
int cur[10010]; 
int dfs(int u, int flow)
{
    if(u == T)return flow; 
    for(int &i = cur[u]; i; i = e[i].nxt)
        if(e[i].c&&dep[e[i].v] == dep[u] + 1)
        {
            int d = dfs(e[i].v, min(e[i].c, flow)); 
            if(d){
                e[i].c -= d; 
                e[i^1].c += d; 
                return d; 
            }
        }
    return 0; 
}
int dinic()
{
    int ans = 0; 
    while(bfs())
    {
        for(int i = S; i <= T; i++)
            cur[i] = head[i]; 
        int d; 
        while(d = dfs(S, 1e9))ans += d; 
    }
    return ans; 
}
int prime[1000010], cnt; 
bool vis[10000010]; 
int x[1010]; 
int posx[1010], posy[1010]; 
int cnt1, cnt2; 
void push(int x)
{
    if(x&1)posx[++cnt1] = x; 
    else posy[++cnt2] = x; 
}
int main(){
    int N = 10000000; 
    vis[1] = true; 
    for(int i = 2; i <= N; i++)
    {
        if(!vis[i])prime[++cnt] = i; 
        for(int j = 1; j <= cnt&&i * prime[j] <= N; j++)
        {
            vis[i * prime[j]] = true; 
            if(i%prime[j] == 0)break; 
        }
    }
    vis[2] = true; 
    int t = read();
    while(t--)
    {
        memset(head, 0, sizeof(head)); 
        cnt1 = cnt2 = 0; tot = 1; 
        int n = read();
        for(int i = 1; i <= n; i++)
        {
            x[i] = read(); 
            if(i == 1||x[i - 1] != x[i] - 1)push(x[i]); 
            if(i> 1&&x[i - 1] != x[i] - 1)push(x[i - 1] + 1); 
        }
        push(x[n] + 1); 
        S = 0, T = cnt1 + cnt2 + 1; 
        for(int i = 1; i <= cnt1; i++)
            insert(S, i, 1); 
        for(int i = 1; i <= cnt1; i++)
            for(int j = 1; j <= cnt2; j++)
                if(!vis[max(posx[i] - posy[j], posy[j] - posx[i])])
                    insert(i, cnt1 + j, 1); 
        for(int i = 1; i <= cnt2; i++)
            insert(cnt1 + i, T, 1); 
        int ans = dinic(); 
        printf("%d
", ans + (cnt1 - ans)/2 * 2 + (cnt2 - ans)/2 * 2 + (cnt1 - ans)%2 * 3); 
    }
    return 0; 
}

以上是关于Problem B: 故障电灯(light)的主要内容,如果未能解决你的问题,请参考以下文章

Light OJ 1034 - Hit the Light Switches(强联通分量)

(light oj 1102) Problem Makes Problem (组合数 + 乘法逆元)

Light oj 1197 - Help Hanzo (素数筛技巧)

JavaScript部分案例

Light oj 1214-Large Division (同余定理)

Light OJ 1025 - The Specials Menu(动态规划-区间dp)