UVALive 6912 Prime Switch 状压DP

本文介绍了一个经典的算法问题PrimeSwitch,该问题涉及通过操作特定开关来最大化点亮灯泡的数量。文章详细解释了问题背景、输入输出格式及样例,并提供了一种结合动态规划与贪心策略的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Prime Switch

题目连接:

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4924

Description

There are lamps (uniquely numbered from 1 to N) and K switches. Each switch has one prime number
written on it and it is connected to all lamps whose number is a multiple of that prime number. Pressing
a switch will toggle the condition of all lamps which are connected to the pressed switch; if the lamp
is off then it will be on, and vice versa. You can press only one switch at one time; in other words,
no two switches can be pressed together at the same time. If you want to press multiple switches, you
should do it one by one, i.e. allowing the affected lamps of the previous switch toggle their condition
first before pressing another switch.
Initially all the lamps are off. Your task is to determine the maximum number of lamps which can
be turned on by pressing one or more switches.
For example, let there be 10 lamps (1 . . . 10) and 2 switches which numbers are 2 and 5 as shown
in the following figure.
In this example:
• Pressing switch 2 will turn on 5 lamps: 2, 4, 6, 8, and 10.
• Pressing switch 5 will turn on 2 lamps: 5 and 10.
• Pressing switch 2 and 5 will turn on 5 lamps: 2, 4, 5, 6, and 8. Note that lamp number 10 will
be turned off as it is toggled twice, by switch 2 and switch 5 (off → on → off).
Among all possible switches combinations, the maximum number of lamps which can be turned on
in this example is 5.

Input

The first line of input contains an integer T (T ≤ 100) denoting the number of cases. Each case begins
with two integers in a line: N and K (1 ≤ K ≤ N ≤ 1, 000), denoting the number of lamps and
switches respectively. The next line contains K distinct prime numbers, each separated by a single
space, representing the switches number. You are guaranteed that the largest number among those
switches is no larger than N

Output

For each case, output ‘Case #X: Y ’, where X is the case number starts from 1 and Y is the maximum
number of lamps which can be turned on for that particular case.
Explanation for 2nd sample case:
You should press switch 2 and 7, such that 11 lamps will be turned on: 2, 4, 6, 7, 8, 10, 12, 16, 18,
20, and 21. There exist some other combinations which can turn on 11 lamps, but none can turn more
than 11 lamps on.
Explanation for 3rd sample case:
There is only one switch, and pressing it will turn 20 lamps on.
Explanation for 4th sample case:
Pressing all switches will turn 42 lamps on, and it is the maximum possible in this case

Sample Input

4
10 2
2 5
21 4
2 3 5 7
100 1
5
100 3
3 19 7

Sample Output

Case #1: 5
Case #2: 11
Case #3: 20
Case #4: 42

Hint

题意

你有n盏灯,有m个开关,开关上面都写着一个质数

那么这个开关就控制着上面写着的数字的倍数。

灯泡按奇数次就亮着,偶数次,就熄灭。

问你最好情况下,最优有多少个灯亮着。

题解:

对于小于等于31的素数,我们状压去跑dp,对于大于的,我们就贪心。

因为大于31的素数一定是不会冲突的,因为上面的数乘起来就大于1000了。

然后这样就行了。

代码

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1000 + 15;
int N,K,pr[maxn],pre[maxn],prime[maxn],primelen,ha[maxn],tot,op[maxn],flag[maxn],temp[maxn];
vector < int > ap;

void Init(){
    memset( ha , -1 , sizeof( ha ) );
    for(int i = 2 ; i < maxn ; ++ i) if(!pre[i]){
        for(int j = i + i ; j < maxn ; j += i) pre[j] = 1;
        prime[ primelen ++ ] = i;
    }
}

int solve( int bit ){
    for(int i = 1 ; i <= N ; ++ i) flag[i] = 0;
    for(int i = 0 ; i < tot ; ++ i) if( bit >> i & 1 ){
        for(int j = op[i] ; j <= N ; j += op[i] ) flag[j] ^= 1;
    }
    for(auto it : ap){
        int add = 0;
        for(int i = it ; i <= N ; i += it) if( flag[i] == 0 ) ++ add ; else -- add;
        if( add > 0 ) for(int i = it ; i <= N ; i += it) flag[i] ^= 1;
    }
    int rs = 0;
    for(int i = 1 ; i <= N ; ++ i) rs += flag[i];
    return rs;
}

int main(int argc,char *argv[]){
    int T,cas=0;
    Init();
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&K);
        for(int i = 0 ; i < K ; ++ i) scanf("%d" , pr + i);
        sort( pr , pr + K );
        tot = 0;ap.clear();
        for(int i = 0 ; i < K ; ++ i) if( pr[i] <= 31 ) op[tot ++ ] = pr[i];else ap.push_back( pr[i] );
        int mx = 0;
        for(int i = 0 ; i < (1 << tot) ; ++ i) mx = max( mx , solve( i ) );
        printf("Case #%d: %d\n", ++ cas , mx);
    }
    return 0;
}

转载于:https://www.cnblogs.com/qscqesze/p/5734130.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值