[Pa2013]Iloczyn

https://www.zybuluo.com/ysner/note/1300802

题面

给定正整数\(n\)和\(k\),问能否将\(n\)分解为\(k\)个不同正整数的乘积。

  • \(n\leq10^9,k\leq20,T\leq4000\)

    解析

    这破题目卡常,删了一堆define快一倍

    可以发现\(12!=479001600>10^9\)。

    所以\(n\)顶多被分解成\(11\)个不同正整数。

常规操作:找出所有约数然后\(O(2^{11})\)枚举加剪枝。

然而我不会搜索啊,\(TLE\)了一个小时。

要加这些剪枝。

  • 乘上后面最小的\(t\)(还没选的数的个数)个数大于\(n\),则\(return\)
  • 搜索过程不是枚举这个数选不选,而是枚举下一次跳到哪个数

只加这些剪枝的后果是要去掉程序中的\(define\)和不必要的库(我还去了读入优化)。

然后\(bzoj\)上由\(TLE\)变成时限一半。。。辣鸡卡常题。。。

然后写总结时又想到一个

  • 如果\(k!>n\),则\(continue\)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2000;
int n,k,sta[N],top,las,f[N][22];
long long jc[22];
int dfs(int x,int t,int s)
{
  if(!t) return s==n;
  for(--t;x+t<=top;++x)
    {
      if(f[x][t]<0) return 0;
      if(1ll*f[x][t]*s>n) return 0;
      if(dfs(x+1,t,sta[x]*s)) return 1;
    }
  return 0;
}
int main()
{
  ios::sync_with_stdio(false);
  int T;cin>>T;
    jc[0]=1;for(int i=1;i<=12;++i) jc[i]=jc[i-1]*i;
  while(T--)
    {
      cin>>n>>k;top=0;
      if(jc[k]>n||k>12) {puts("NIE");continue;}
      for(int i=1;i*i<=n;++i)
        if(n%i==0)
      {
            sta[++top]=i;
        if(i*i!=n) sta[++top]=n/i;
      }
      sort(sta+1,sta+1+top);
      for(int i=1;i<=top;++i)
    {
      long long t=1;
      for(int j=0;j<k&&i+j<=top;f[i][j++]=t)
        if(t>0)
        {
          t*=sta[i+j];
          if(t>n) t=-1;
        }
    }
      puts(dfs(1,k,1)?"TAK":"NIE");
    }
  return 0;
}

原文地址:https://www.cnblogs.com/yanshannan/p/9744019.html

时间: 2024-11-10 14:02:57

[Pa2013]Iloczyn的相关文章

BZOJ3733 : [Pa2013]Iloczyn

首先将$n$的约数从小到大排序,设$dfs(x,y,z)$表示当前可以选第$x$个到第$m$个约数,还要选$y$个,之前选的乘积为$z$是否可能. 爆搜的时候,如果从$x$开始最小的$y$个相乘也超过了$n$,那么就不合法,加上这个剪枝即可. #include<cstdio> #include<algorithm> #define N 2000 int T,n,k,m,i,j,q[N],f[N][22]; int dfs(int x,int y,int z){ if(!y)retu

省选之前的未完成的计划(截至到省选)

PLAN OF THE COMING HEOI good problems:-bzoj4823:[Cqoi2017]老C的方块 [*]-bzoj3171:[Tjoi2013]循环格 [*]-bzoj4200:[Noi2015]小园丁与老司机 [*]-bzoj1061:[Noi2008]志愿者招募 [*]-bzoj3600:没有人的算术 [*]-bzoj2806:[Ctsc2012]Cheat [*]-bzoj2219:数论之神 [*]-bzoj2595:[Wc2008]游览计划 [*]-bzoj

波兰题目补全计划

Introduce 本人比较喜欢做波兰的题目,感觉这些题目十分清真,思维也比较好.欢迎同样喜欢波兰题目的OIer来交流.以下是我有记录地刷过的题目. 比较好的题吧:BZOJ #3746.[POI2015]Czarnoksi??nicy okr?g?ego sto?u source:XXII OI - Etap I - Zadanie Czarnoksi??nicy okr?g?ego sto?u notes: 动态规划我的题解http://www.cnblogs.com/TSHugh/p/882

【PA2013】【BZOJ3733】Iloczyn

Description 给定正整数n和k,问是否能将n分解为k个不同正整数的乘积 Input 第一行一个数T(T<=4000)表示測试组数 接下来T行每行两个数n(n<=10^9),k(k<=20) Output 输出T行,若能够被分解,输出"TAK"否则输出"NIE" Sample Input 3 15 2 24 4 24 5 Sample Output TAK TAK NIE HINT Source 如今BZOJ上不去没有中文题面也没法在BZO

bzoj3713[PA2014]Iloczyn*

bzoj3713[PA2014]Iloczyn 题意: 判断给定的数字能否被表示成两个斐波那契数的乘积.n≤10^9 题解: 开始在想有没有什么根号级算法,后来想知道斐波那契数列10000位有多大,结果爆long long了……实际上斐波那契数列到45位就大于10^9了.所以直接枚举即可. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) fo

BZOJ 3713: [PA2014]Iloczyn( 枚举 )

斐波那契数列<10^9的数很少很少...所以直接暴力枚举就行了... ------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; ++i ) #d

3713: [PA2014]Iloczyn

3713: [PA2014]Iloczyn Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 327  Solved: 181[Submit][Status][Discuss] Description 斐波那契数列的定义为:k=0或1时,F[k]=k:k>1时,F[k]=F[k-1]+F[k-2].数列的开头几项为0,1,1,2,3,5,8,13,21,34,55,…你的任务是判断给定的数字能否被表示成两个斐波那契数的乘积. Input 第一行包含一个

BZOJ3736 : [Pa2013]Karty

显然只需要考虑与障碍点相邻的格子,通过旋转坐标系,可以只考虑障碍点在格子上方的情况. 悬线法求出每个点往上的最长延伸距离$x$,以及往左往右的延伸距离$y$. 那么当$r\geq x$时,$c$至多为$y$. 特别地,当某个点下方也是障碍点的时候,$r$不能超过$x$. 维护出每个$r$对应的最大的$c$即可. 时间复杂度$O(nm)$. #include<cstdio> #include<algorithm> const int N=2505; int n,m,i,j,k,l[N

BZOJ 3736: [Pa2013]Karty

Description 一个0/1矩阵,求能覆盖所有 \(1\) ,同时不覆盖所有 \(0\) 的矩阵,使这个面积最大. Sol DP/悬线法. 首先,所求的矩阵一定可以覆盖所有贴边的悬线. 用悬线法求出,高度为 \(r\) 最大的 \(c\) ,宽度为 \(c\) 最大的高度. 上下左右都要做一遍,然后更新统计答案. 上下的时候统计的是每一个高度,左右的时候统计的是每一个宽度. 这样就可以保证所有矩阵都是一个合法的矩阵了. 我多开了几个数组,发现空间炸了...然后我就开始滚了... Code