J установить выбор

Тема: Найдите все подмножества {1, 2, 3, 4, 5}, которые удовлетворяют следующим условиям: Если x находится в этом подмножестве, то 2x и 3x не могут быть в этом подмножестве. (Результат по модулю 1e9 + 1)

Анализ:

  Прежде всего, какие цифры приведут к исключению? (Я не могу выбрать это, если я выберу это) Соотношение, очевидно, 2 или 3.

  Во-вторых, легко понять, что каждая из этих форм имеет вид 1,2,4,8,3,6,9 ... Этот вид серии, которая простирается наружу через * 2 * 3 с небольшим числом Там нет никаких помех между двумя

  Например, это может быть 1, 2, 4, 8, 3, 9, 27, 6, 12, 24 ...

  Не должно быть пересечения между ним и теми, кто простирается от 5, 5, 10, 20, 15, 30, 60 ...

  Тогда легко подумать о принципе умножения здесь,

  Другими словами, мы решили результат каждой такой последовательности только после умножения ее на конечный результат

  Так как вы решаете это для каждого?

  Во-первых, если только отношение 2 не может появиться в подмножестве,

  Первое чувство должно быть "Эти выборы не будут закончены"

  Конечно, следующая секунда вернется. Очевидно, она не выйдет с первого взгляда (кроме dalao, такого как gjk)

 

  

 

 

 

 

 

  Большинство из этих двух вопросов прошло ... Теперь все должны стремиться перебить меня "Является ли эта вещь ослабленной версией вопроса B, которая не нарушает друг друга (даже ослаблена до линейной)" "Я буду играть эту вещь с закрытыми глазами" ,

 

  Ну, на самом деле, это использование двоичного перечисления, чтобы проверить , считается ли каждая позиция в n 2 ^ i . Очевидно, что если k & (k >> 1)! = 0 или k & (k << 1)! = 0, это недопустимо Да, иначе это законно

  Так что же нам теперь делать с лимитом 3?

  Учтите, что до добавления этого предела каждая последовательность с общим отношением 2 в качестве первого члена не зависит друг от друга.

  После добавления этого лимита каждый элемент в этой последовательности чисел связан с ним * 3, он * 9 ...

  Это оказалось число (точка), а после добавления первого лимита оно стало последовательностью (линией)

  Теперь это последовательность чисел (строк), плюс предел, то становится?

  Да, это становится матрицей

  Так что это также заполнило начальную дыру, почему он должен считать меньшее число, он * 2 * 3 вместе

  И теперь мы знаем, фактически, последовательность, о которой он начал говорить, это не последовательность, а матрица, которая, вероятно, такова

  1 2 4 8 16

  3 6 12 24 48

  9 18 36 72 144

  ......

  И как это может исключить незаконных?

  «Разве это не ослабленная версия Вопроса B» «Хорошо, я увижу тебя снова»

  Это верно, вам нужно всего лишь использовать dp, чтобы делать все, что вы хотите. Я считаю, что конкретные условия суждения могут быть выполнены вашими ногами. Да, j & k! = 0 недопустимо, в противном случае это законно

  Наконец, разобраться

  Сначала мы должны перечислить «наименьшее число», здесь я использую, чтобы определить, не делится ли это число на 2 или 3,

  Здесь похоже на линейное сито. Очевидно, что если это число можно разделить на 2 или 3, он должен иметь имя с именем x / 2 или x / 3, чтобы действовать как «минимальное число»

  После перечисления наименьшего числа первый столбец будет x, x * 3, x * 9, ...

  Затем он считает количество столбцов в каждой строке (x * (3 ^ i) * (2 ^ j) <= n)

  Наконец, просто нажмите dp и просто сделайте это.

  На самом деле, этот вопрос в основном закончен, но я не знаю, является ли это причиной моей еды

  Вот краткое введение в некоторые оптимизации (детали кода)

  1. Сохраните состояние вашего однострочного суждения с массивом

  Например, я изначально написал для (0-> 1 << k) if (k & ……) dp [k] ……   

  Но теперь нам нужно только предварительно обработать после for (0-> q.size ()) dp [k] ……

  2. Модуль-> Вычитание

  

 

   

 

   Очевидно, что вычитание намного быстрее, чем взятие модуля

  3. Используйте переменные вместо массивов и, наконец, присвойте значения

 

 

 

   Очевидно намного быстрее

  4. Назначьте начальные значения во время работы (не используйте memset, но назначьте начальные значения перед использованием)

 

 

 

 

 

   Это не немного хуже, не ленитесь в одночасье!

  

  Наконец, в конце позвольте мне рассказать о коде, который имеет дело с некоторыми деталями

  1. Выберите «наименьшее число»

  

 

  Я говорил это раньше

  2. Подсчитайте, сколько столбцов в строке

  

 

  Здесь j - «минимальное число», фактически это должен быть логарифм n / j, основанный на 2,

  Я использовал формулу изменения базы, кажется, что у Curry нет функции base 2, только натуральный логарифм и общий логарифм

  В частности, почему это так категорично, я думаю, что на самом деле нечего сказать. , ,

  3. Когда завершать цикл перечисления текущей строки

  

 

  注意,这里的last我有用的,所以最好不要写在循环的第二个分号里(当然这么写再稍微判断一下也是可以的)

  4.如何枚举上一层状态,到哪结束

  这就是last的意义——记录上一层到q的第多少个,也就是有多少种状态

 

 

  当然这里的last你看我整个循环,其实他是有可能从上面for的第二个分号出去的,所以开始last要赋成q_cnt而不是0,-1之类无意义的值,防止last还没被赋值就跳出来

  这次真没了

代码:

#include<cstdio>
#include<cmath>
using namespace std;

#define ll long long

const int maxk=2e1+1;
const int mod=1e9+1;
const int maxn=1e5+1;

int dp[maxn][maxk];
int q[maxn];

int pd(int x)
{
    if(x&(x<<1)||x&(x>>1)) return 0;
    return 1;
}

int pdd(int x,int y)
{
    if(x&y) return 0;
    return 1;
}

int main()
{
    int n;
    scanf("%d",&n);
    ll ji=1;
    int hh=(int)(log(n)/log(2))+1;
    int q_cnt=0;
    for(int i=0;i<1<<hh;++i) if(pd(i)) q[q_cnt++]=i;
    for(int i=1;i<=n;++i) if(i%2&&i%3)
    {
        int last=q_cnt,p=0;
        for(int j=i;j<=n;j*=3,++p)
        {
            int now=(int)(log(n/j)/log(2))+1;
            for(int k=0;k<q_cnt;++k)
            {
                if(q[k]>=1<<now)
                {
                    last=k;
                    break;
                }
                if(!p) dp[k][p]=1;
                else
                {
                    int nowans=0;
                    for(int t=0;t<last;++t) if(pdd(q[k],q[t]))
                    {
                        nowans+=dp[t][p-1];
                        if(nowans>=mod) nowans-=mod;
                    }
                    dp[k][p]=nowans;
                }
            }
        }
        int ans=0;
        for(int j=0;j<last;++j)
        {
            ans+=dp[j][p-1];
            if(ans>=mod) ans-=mod;
        }
        ji*=(ll)ans,ji%=(ll)mod;
    }
    printf("%lld",ji);
    return 0;
}

 

рекомендация

отwww.cnblogs.com/lin4xu/p/12735448.html