J establecer selección

Tema: Encuentre todos los subconjuntos de {1, 2, 3, 4, 5} que satisfagan las siguientes condiciones: Si x está en este subconjunto, entonces 2x y 3x no pueden estar en este subconjunto. (El resultado es el módulo 1e9 + 1)

Análisis:

  En primer lugar, ¿qué tipo de números causarán exclusión? (No puedo elegir eso si elijo esto) La relación es obviamente 2 o 3.

  En segundo lugar, es fácil entender que cada una de estas formas es 1,2,4,8,3,6,9 ... Este tipo de serie que se extiende hacia afuera hasta * 2 * 3 con un número pequeño, son dos No hay interferencia entre los dos

  Por ejemplo, puede ser 1, 2, 4, 8, 3, 9, 27, 6, 12, 24 ...

  No debe haber intersección entre él y aquellos que se extienden desde 5, 5, 10, 20, 15, 30, 60 ...

  Entonces es fácil pensar en el principio de multiplicación aquí,

  En otras palabras, resolvimos el resultado de cada secuencia solo después de multiplicarlo, es el resultado final

  Entonces, ¿cómo lo resuelves para cada uno?

  Primero, si solo la proporción de 2 no puede aparecer en el subconjunto,

  El primer sentimiento debe ser "Esta elección no se terminará"

  Por supuesto, el próximo segundo volverá. Obviamente, no saldrá de un vistazo (a excepción de dalao como gjk)

 

  

 

 

 

 

 

  La mayoría de estas dos preguntas han pasado ... Ahora todos deberían estar ansiosos por interrumpirme "¿Es esto una versión debilitada de la pregunta B que no se viola entre sí (incluso debilitada a lineal)" "Jugaré esto con los ojos cerrados" ,

 

  Bueno, de hecho, es usar la enumeración binaria para verificar si cada posición en el n 2 ^ i se cuenta. Obviamente, si k & (k >> 1)! = 0 o k & (k << 1)! = 0, es ilegal. Si, de lo contrario es legal

  Entonces, ¿qué debemos hacer ahora con un límite de 3?

  Tenga en cuenta que antes de agregar este límite, cada secuencia con una proporción común de 2 ya que el primer término no se ve afectado entre sí

  Después de agregar este límite, cada elemento en esta secuencia de números está relacionado con él * 3, él * 9 ...

  Resultó ser un número (punto), y después de agregar el primer límite, se convirtió en una secuencia (línea)

  Ahora es una secuencia de números (líneas), más un límite, entonces se convierte en?

  Sí, se convierte en una matriz (cara)

  Entonces esto también llenó el hoyo inicial, ¿por qué debería considerar un número menor?

  Y ahora sabemos, de hecho, la secuencia de la que comenzó a hablar no es una secuencia sino una matriz, que probablemente sea así

  1 2 4 8 16

  3 6 12 24 48

  9 18 36 72 144

  ......

  ¿Y cómo puede esto descartar los ilegales?

  "¿Todavía no es una versión debilitada de la pregunta B" "Está bien, lo veré de nuevo"

  Así es, solo necesitas usar dp para hacer lo que quieras. Creo que las condiciones de juicio específicas se pueden jugar con tus pies. Sí, j & k! = 0 es ilegal, de lo contrario es legal

  Finalmente, resuélvelo

  Primero tenemos que enumerar el "número más pequeño", aquí lo uso para determinar si este número no es divisible por 2 o 3,

  Aquí es similar a un tamiz lineal. Obviamente, si este número puede dividirse por 2 o 3, debe tener un nombre llamado x / 2 o x / 3 para actuar como el "número mínimo"

  Después de enumerar el número más pequeño, la primera columna es x, x * 3, x * 9, ...

  Luego cuenta el número de columnas en cada fila (x * (3 ^ i) * (2 ^ j) <= n)

  Finalmente, solo presione dp y simplemente hágalo.

  De hecho, esta pregunta básicamente ha terminado, pero no sé si es la razón de mi comida, y lo he estado haciendo durante mucho tiempo.

  Aquí hay una breve introducción a varias optimizaciones (detalles del código)

  1. Guarde el estado de su juicio de línea única con una matriz

  Por ejemplo, originalmente escribí para (0-> 1 << k) if (k & ......) dp [k] ......   

  Pero ahora solo necesitamos preprocesar después para (0-> q.size ()) dp [k] ......

  2. Módulo-> Resta

  

 

   

 

   Obviamente, la resta es mucho más rápida que tomar el módulo

  3. Use variables en lugar de matrices y finalmente asigne valores

 

 

 

   Obviamente mucho más rápido

  4. Asigne valores iniciales mientras trabaja (no use memset, pero asigne valores iniciales antes de usar)

 

 

 

 

 

   Esto no es un poco peor, ¡no seas perezoso de la noche a la mañana!

  

  Finalmente, al final, déjenme hablar sobre el código que trata con ciertos detalles

  1. Seleccione el "número más pequeño"

  

 

  Lo dije antes

  2. Calcule cuántas columnas hay en la fila

  

 

  Aquí j es el "número mínimo", de hecho, debería ser el logaritmo de n / j basado en 2,

  Utilicé una fórmula de cambio de base, parece que Curry no tiene una función de base 2, solo logaritmo natural y logaritmo común

  Específicamente por qué es tan categórico, creo que realmente no hay nada que decir. . .

  3. Cuándo terminar el ciclo de la enumeración de línea actual

  

 

  注意,这里的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;
}

 

Supongo que te gusta

Origin www.cnblogs.com/lin4xu/p/12735448.html
Recomendado
Clasificación