zoukankan      html  css  js  c++  java
  • UVALive 6912 Prime Switch 状压DP

    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
    ", ++ cas , mx);
    	}
    	return 0;
    }
  • 相关阅读:
    《三体》推荐
    低调做人,高调做事
    注意力的培养是学校教学的真正目的
    【RTP.NET入门系列 一】接收第一个RTP包。
    MapX开发日记(三)GPS项目终于有了眉头
    【RTP.NET入门系列 二】接收第一个RTP帧。
    10.04 flash 乱码 问题
    10.04 中文输入发问题。
    通过值类型进行Timer类的线程的同步。
    关于ManualResetEvent信号机制。
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5734130.html
Copyright © 2011-2022 走看看