安徽师大附中%你赛day7 T2 乘积 解题报告
乘积
题目背景
\(\mathrm{Smart}\) 最近在潜心研究数学, 他发现了一类很有趣的数字, 叫做无平方因子数。 也就是这一类数字不能够被任意一个质数的平方整除, 比如\(6\)、\(7\)、\(10\)都是无平方因子数, 而\(12\)则不是。
题目描述
所以 \(\mathrm{Smart}\) 在思考一个问题——选择不超过 \(K\) 个 \(N\) 以内的正整数乘起来, 使得乘积是一个无平方因子数, 有多少种取法? (每个数只能取一次)
输入输出格式
输入格式
第一行一个整数 \(T\) 表示数据组数。
接下来 \(T\) 行, 每行两个整数 \(N\),\(K\), 意思如题面所述。
输出格式
对于每一组数据, 输出一个整数表示取法的方案数对 \(10^9+7\) 取模后的数值。
说明
\(10\%\)的数据: \(N≤8\);
\(40\%\)的数据: \(N≤16\);
\(70\%\)的数据: \(N≤30\);
\(100\%\)的数据: \(1≤T≤5\); \(1≤K≤N≤500\)。
70pts 有非常多种搞法,然而状压是最难写的但是最可能继续玩出正解的。。
可是我太菜,比赛时写了个麻烦的状压
\(dp[i][j][s]\)代表前\(i\)个数选择了\(j\)个素数状态为\(s\)的方案数
Code:
#include <cstdio>
#include <cstring>
const int N=502;
int num[30][10],dat[30];
int pri[N],is[N],v[N],cnt,tot;
int div[N][100];
void init()
{
for(int i=2;i<=500;i++)
{
if(!is[i])
{
pri[++cnt]=i;
v[i]=i;
}
for(int j=1;j<=cnt&&i*pri[j]<=500;j++)
{
if(v[i]<pri[j]) break;
v[i*pri[j]]=pri[j];
is[i*pri[j]]=1;
}
}
for(int i=2;i<=500;i++)
{
int t=i;
for(int j=1;j<=cnt;j++)
while(t%pri[j]==0)
div[i][j]++,t/=pri[j];
}
for(int i=2;i<=33;i++)
{
int flag=1;
for(int j=1;j<=12;j++)
if(div[i][j]>1) {flag=0;break;}
if(!flag) continue;
++tot;
dat[tot]=i;
for(int j=1;j<=12;j++)
if(div[i][j])
num[tot][j]=1;
}
}
int mod=1e9+7;
int n0,k;
int dp[20][20][1200];
void work()
{
scanf("%d%d",&n0,&k);
int l=0,n=0;
for(int i=1;;i++)//素数长度上界
{
if(pri[i]<=n0) ++l;
else break;
}
for(int i=1;;i++)//选数个数上界
{
if(dat[i]<=n0) ++n;
else break;
}
k=(k<=n?k:n);
memset(dp,0,sizeof(dp));
for(int i=0;i<=n;i++) dp[i][0][0]=1;
int ans=0;
for(int i=1;i<=n;i++)//前i个数
for(int j=1;j<=k;j++)//取了j个
for(int s=1;s<1<<l;s++)//素数集合状态
{
int las=s,flag=1;
dp[i][j][s]=dp[i-1][j][s];
for(int q=1;q<=l;q++)
if(num[i][q])//如果这一位是1
{
if((s>>q-1)&1) las^=1<<q-1;//变成0
else {flag=0;break;}
}
if(flag) (dp[i][j][s]+=dp[i-1][j-1][las])%=mod;
}
for(int i=1;i<=k;i++)
for(int s=1;s<1<<l;s++)
{
if(i!=k) (ans+=dp[n][i][s]<<1)%=mod;
else (ans+=dp[n][i][s])%=mod;
}
printf("%d\n",ans+1);
}
int main()
{
freopen("mult.in","r",stdin);
freopen("mult.out","w",stdout);
init();
int t;
scanf("%d",&t);
while(t--)
work();
return 0;
}
而正解只是运用分组背包的思想
注意到大于19的质数只可能出现一个
那我们实际上就只需要找到状压2,3,5,7,11,13,17,19这几个素数就行了
其他大于19的素数按照这个素数进行分组,剩下的同时按前几个素数做就可以了
很巧妙的思想,然而数据不好造,答案一样的期望炒鸡高
Code:
#include <cstdio>
#include <cstring>
#include <vector>
#define ll long long
const int N=500;
const ll mod=1e9+7;
const int pri[9]={0,2,3,5,7,11,13,17,19};
using namespace std;
vector <int > g[N+10];
int belong[N+10],sta[N+10],n,k;
void init()
{
memset(belong,0,sizeof(belong));
memset(sta,0,sizeof(sta));
for(int i=1;i<=N;i++) g[i].clear();
for(int i=1;i<=n;i++)
{
belong[i]=i;
for(int j=1;j<=8;j++)
{
if(i%(pri[j]*pri[j])==0) {sta[i]=-1;break;}
else if(i%pri[j]==0) {belong[i]/=pri[j];sta[i]|=1<<j-1;}
}
}
for(int i=1;i<=n;i++)
{
if(~sta[i])
{
if(belong[i]!=1)
g[belong[i]].push_back(sta[i]);
else
g[i].push_back(sta[i]);
}
}
}
ll dp[N+10][256];
void work()
{
scanf("%d%d",&n,&k);
init();
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=k;j;j--)
for(int s=255;~s;s--)
{
if(!dp[j][s]) continue;
for(int l=0;l<g[i].size();l++)
{
int now=g[i][l];
if(now&s) continue;
(dp[j][now|s]+=dp[j-1][s])%=mod;
}
}
}
ll ans=0;
for(int i=1;i<=k;i++)
for(int s=0;s<=255;s++)
(ans+=dp[i][s])%=mod;
printf("%lld\n",ans);
}
int main()
{
//freopen("mult.in","r",stdin);
//freopen("mult.out","w",stdout);
int t;scanf("%d",&t);
while(t--)
work();
return 0;
}
2018.8.20
安徽师大附中%你赛day7 T2 乘积 解题报告的更多相关文章
- 安徽师大附中%你赛day9 T2 富 解题报告
富 题目背景 出于某些原因, 苟先生在追杀富先生. 题目描述 富先生所在的地方是一个\(n\times m\)的网格,苟先生排出了他的狼狗大军,共有\(k\)条狗,第\(i\)条狗所在的位置为\((x ...
- 安徽师大附中%你赛day9 T3 贵 解题报告
贵 问题描述 苟先生的狼狗大军没有追上富先生, 所以他把它们都解雇了, 决定去雇佣一些更好的狗, 不过狗可是很贵的.苟先生有 \(w\) 元钱, 有 \(n\) 条狗可以雇佣, 第 \(i\) 条狗有 ...
- 安徽师大附中%你赛day3T1 怜香惜玉 解题报告
怜香惜玉 题意: 已知 \(f(x)=\frac{2 \times \sum_{(i,x)=1}^x i}{φ(x)}\) 先给定数据组数\(t\)和\(k\) 每组数据给出\(n\),求\(\sum ...
- 安徽师大附中%你赛day2T3 巧克力 解题报告
巧克力 题目描述 小\(T\)有\(N\)块巧克力, 每块巧克力上都有一句话(由小写英文字母组成,不含标点) .现在每块巧克力都断成了若干截,更糟糕的是,有一些碎片丢失了 ,但是剩下的碎片之间的顺序是 ...
- 安徽师大附中%你赛day6 T3 Hamsters [POI2010]CHO-Hamsters 解题报告
[POI2010]CHO-Hamsters 题意: 给出n个互不包含的字符串,要求你求出一个最短的字符串S,使得这n个字符串在S中总共至少出现m次,问S最短是多少? 范围: \(1 \le n \le ...
- 安徽师大附中%你赛day5 T3 树上行走 解题报告
树上行走 题目背景 \(\mathrm{Smart}\) 的脑洞非常大, 经常幻想出一些奇怪的东西. 题目描述 某一天,\(\mathrm{Smart}\) 幻想出了一棵没有边际的二叉树,脑补着在那棵 ...
- 安徽师大附中%你赛day4T2 演讲解题报告
演讲 题目背景: 众所周知,\(\mathrm{Zdrcl}\)是一名天天\(\mathrm{AK}\)的高水平选手. 作为一民长者,为了向大家讲述自己\(\mathrm{AK}\)的经验,他决定在一 ...
- 安徽师大附中%你赛day4T1 金字塔 解题报告
金字塔 题目背景: \(Zdrcl\)带着妹子们来到了胡夫金字塔周边旅游, 发现这里正在进行一个有关金字塔的游戏 题目描述: 游戏规则如下: 1. 这里的金字塔是一个 \(N\) 阶的二维金字塔. 2 ...
- 「2018-12-02模拟赛」T2 种树 解题报告
2.种树(tree.pas/cpp/in/out) 问题描述: Fanvree 很聪明,解决难题时他总会把问题简单化. 例如,他就整天喜欢把图转化为树.但是他不会缩环,那他怎么转化呢? 这是一个有 n ...
随机推荐
- mysql在cmd里中文乱码解决办法
右边画红线部分中文已经乱码,左边红线里中文则完美显示出来了. 解决办法 用set names utf-8: 效果如图
- SpringBoot学习(1)
springboot的自动配置功能,主要流程如下: 1 启动的时候加载我们的主配置类,也就是我们的入口类:从而开启我们的自动配置配置功能,这个是通过@EnableAutoConfiguration注解 ...
- C语言实现简易扫雷
首先,写代码之前要将整体思路写出来: 扫雷游戏:1.需要两个二维数组,一个用来展示,一个用来放雷; 2.整体骨架在代码中都有注释说明; 3.游戏难度比较简单,适合初学者观看,如果有大佬看明白,可以指点 ...
- 006---Python基本数据类型--集合
集合 .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px ...
- Python3 模块、包调用&路径
''' 以下代码均为讲解,不能实际操作 ''' ''' 博客园 Infi_chu ''' ''' 模块的优点: 1.高可维护性 2.可以大大减少编写的代码量 模块一共有三种: 1.Python标准库 ...
- Python3.6中PyInstaller不能对文件进行打包问题
上篇文章<itchat和matplotlib的结合使用爬取微信信息>是用python爬取信息得到微信朋友的信息,并且用matplotlib统计信息进行画图,所以今天想将它打包成.exe可执 ...
- shell -- 大括号和小括号
在这里我想说的是几种shell里的小括号,大括号结构和有括号的变量,命令的用法,如下: 1.${var} 2.$(cmd) 3.()和{} 4.${var:-string},${var:+string ...
- cachel-control
nodejs: res.set('Cache-Control', 'public, max-age=31557600'); express全局设置: app.use(express.sta ...
- 「日常训练」「小专题·USACO」 Wormholes(1-4)
题意 之后补充. 分析 这是一条很好的考察递归(或者说搜索)的题目.它的两个过程(建立初步解,验证)都用到了递归(或者说运用递归可以相当程度的减少代码量). 具体实现见代码.注意,为了使用std::p ...
- tp5 项目实战 初级 文字步骤
项目实战 环境搭建 新建模块 admin 新建文件夹 controller model view View 中新建 user index 相关样式 js 图片 放入publ ...