BZOJ2327: [HNOI2011]勾股定理

Description


题解Here!

这是一道神题。。。

我一开始把题目看错了,我以为是在$n$根木棒中选两个$i,j$满足$gcd(i,j)==1$,并且存在$k$使得$i^2+j^2==k^2$。

我说这不是网络流的沙茶题嘛?

然后数据范围$n<=10^6$。。。

怎么这么大?就算建图建完了,$Dinic$好像也会$TLE$,预流推进可能都会$TLE$。。。

然后回头看题——$MD$,我就是个$zz$。。。

选取若干个。。。

于是这题就比较好做了。

这里有一篇$YDC$巨佬的博客讲的比我好:链接

首先要预处理出$10^6$以内的勾股数对。

根据初中的经验,我们有:$$(m^2-n^2)^2+(2mn)^2=(m^2+n^2)^2$$

这个应该都会证吧,全部拆开就好了。

于是一对互质勾股数$(a,b)$与一对$(i,j)$应满足$$a=j^2-i^2,b=2\times i\times j,c=j^2+i^2,gcd(i,j)==1,i<j,\text{i和j不同奇偶}$$

我们枚举$i,j$,由于$i\times j<=\frac{10000000}{2}$,并且$gcd$的复杂度上限是$\log_2n$,一般不会达到,所以就是$500000\times \log_2 500000<500000\times 20=10^7$的复杂度。

我们对于互质勾股数$(a,b)$,在$a,b$间连边。

我们假设他们构成了一片森林,那么题目变成在森林中选点且互不相邻了,跟P1352 没有上司的舞会很像,经典树形$DP$。

但是自从我发现这个不是基环无向树就不想做了。

设$dp[i][0]$表示在$i$这棵子树上不选$i$的方案数,$dp[i][1]$表示在$i$这颗子树上选$i$的方案数。

状态转移长这样:
$$dp[i][0]=(dp[v_1][0]+F[v_1][1])\times (dp[v_2][0]+dp[v_2][1])\times ...$$
$$dp[i][1]=(2^{num[i]}-1)\times dp[v_1][0]\times dp[v_2][0]\times ...$$

$num[i]$表示$i$出现了几次。

我们发现我们建的图将构成一片森林。

假设森林里每颗树的根是$rt_1,rt_2,...rt_k$,那么答案就是:
$$(dp[rt_1][0]+dp[rt_1][1])\times(dp[rt_2][0]+dp[rt_2][1])\times ...\text{之后再减1,即去掉空集}$$

$BUT$!这么做是$30$分。

我当时懵的一批啊。。。感觉这方法行得通吗???

然后我发现一个智障一样的问题——图并不一定是树,可能有环。。。

靠!这个坑。。。

接下来就开始乱搞了。。。

对于一条回边$(u,v)$,就像$tarjan$求强连通中的$dfn[v]<dfn[u]$一样,我们把$u,v$标记一下加入点集$stack$,把这条边删掉。

之后$2^{|stack|}$枚举每个点的选择情况,在合法的情况下套用树形$DP$。

这个时候由于是同一棵树,所以用加法原理而不是乘法原理,即每次统计的答案用个变量累加,最后乘以这个变量。

这题就做完了

吗?

没有!

但是因为数据水的原因,出题人强行把$NP$的题出成了普通题。。。

所以这题就当过了吧。。。

HN的出题人真是不负责任。。。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#define MAXN 1000010
#define MOD 1000000007
using namespace std;
vector<int> stack;
int n,c=1,d=1,T;
int head[MAXN],deep[MAXN],vis[MAXN],num[MAXN];
long long bit[MAXN],dp[MAXN][2];
bool used[MAXN],choose[MAXN];
struct Edge{
int next,to;
}a[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline long long sqr(long long x){return x*x;}
int gcd(int x,int y){
if(!y)return x;
return gcd(y,x%y);
}
inline void add(int x,int y){
a[c].to=y;a[c].next=head[x];head[x]=c++;
a[c].to=x;a[c].next=head[y];head[y]=c++;
}
void build(){
int m=MAXN-10;
for(int i=1;i<=m/2;i++)
for(int j=i+1;j<=m/2/i&&sqr(j)-sqr(i)<=m;j++)
if(((i&1)!=(j&1))&&gcd(i,j)==1)add(2LL*i*j,sqr(j)-sqr(i));
bit[0]=1;
for(int i=1;i<=m;i++)bit[i]=(bit[i-1]<<1)%MOD;
}
inline void insert(int x){
if(!used[x]){
used[x]=true;
stack.push_back(x);
}
}
bool check(int u,int f){
vis[u]=T;
for(int i=head[u];i;i=a[i].next){
int v=a[i].to;
if(v==f||!num[v])continue;
if(choose[u]&&choose[v])return false;
if(vis[v]!=T)if(!check(v,u))return false;
}
return true;
}
void dfs1(int x,int f){
deep[x]=d++;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(!num[v]||v==f)continue;
if(!deep[v])dfs1(v,x);
else if(deep[v]<deep[x]){insert(x);insert(v);}
}
}
void dfs2(int x,int f){
vis[x]=T;
dp[x][0]=1;
dp[x][1]=(bit[num[x]]-1+MOD)%MOD;
if(used[x]){
if(choose[x])dp[x][0]=0;
else dp[x][1]=0;
}
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(v==f||!num[v]||vis[v]==T)continue;
if(vis[v]!=T)dfs2(v,x);
dp[x][0]=dp[x][0]*(dp[v][0]+dp[v][1])%MOD;
dp[x][1]=dp[x][1]*dp[v][0]%MOD;
}
}
void dfs3(int i,int m,int x,long long &ans){
if(i==m){
T++;
if(check(x,-1)){
T++;
dfs2(x,-1);
ans=(ans+dp[x][0]+dp[x][1])%MOD;
}
return;
}
choose[stack[i]]=false;
dfs3(i+1,m,x,ans);
choose[stack[i]]=true;
dfs3(i+1,m,x,ans);
}
long long solve(int x){
stack.clear();
dfs1(x,-1);
int m=stack.size();
long long ans=0;
dfs3(0,m,x,ans);
return ans;
}
void work(){
long long ans=1;
for(int i=1;i<=MAXN-10;i++)if(num[i]&&!deep[i])ans=ans*solve(i)%MOD;
printf("%lld\n",(ans-1+MOD)%MOD);
}
void init(){
n=read();
for(int i=1;i<=n;i++){
int x=read();
num[x]++;
}
}
int main(){
build();
init();
work();
return 0;
}

BZOJ2327: [HNOI2011]勾股定理的更多相关文章

  1. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  2. bzoj-2338 2338: [HNOI2011]数矩形(计算几何)

    题目链接: 2338: [HNOI2011]数矩形 Time Limit: 20 Sec  Memory Limit: 128 MB Description Input   Output 题意: 思路 ...

  3. JavaScript数学揭密之函数与勾股定理

    一.函数 function show(n){ return n*2; } alert( show(2) ); alert( show(3) ); alert( show(4) ); 二.勾股定理 1. ...

  4. 【概率DP/高斯消元】BZOJ 2337:[HNOI2011]XOR和路径

    2337: [HNOI2011]XOR和路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 682  Solved: 384[Submit][Stat ...

  5. bzoj2326: [HNOI2011]数学作业

    矩阵快速幂,分1-9,10-99...看黄学长的代码理解...然而他直接把答案保存在最后一行(没有说明...好吧应该是我智障这都不知道... #include<cstdio> #inclu ...

  6. BZOJ2337: [HNOI2011]XOR和路径

    题解: 异或操作是每一位独立的,所以我们可以考虑每一位分开做. 假设当前正在处理第k位 那令f[i]表示从i到n 为1的概率.因为不是有向无环图(绿豆蛙的归宿),所以我们要用到高斯消元. 若有边i-& ...

  7. Mac Dock 效果及原理(勾股定理)

    这个是苹果机上的 Dock 效果,Windows 上也有一款专门的模拟软件——RocketDock. 代码如下: <!doctype html> <html> <head ...

  8. BZOJ 2329: [HNOI2011]括号修复( splay )

    把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, ...

  9. BZOJ 2337: [HNOI2011]XOR和路径( 高斯消元 )

    一位一位考虑异或结果, f(x)表示x->n异或值为1的概率, 列出式子然后高斯消元就行了 --------------------------------------------------- ...

随机推荐

  1. 算法复习——2—sat(bzoj2199)

    题目: Description 由于对Farmer John的领导感到极其不悦,奶牛们退出了农场,组建了奶牛议会.议会以“每头牛 都可以获得自己想要的”为原则,建立了下面的投票系统: M只到场的奶牛 ...

  2. 刷题总结——shortest(ssoi)

    题目: 题目背景 SOURCE:NOIP2015-SHY-3 题目描述 给定一张 n 个点的有向带权完全图,和一个数组 a[] ,请按顺序删除数组中的点,请求出在删除点 a[i] 以前,所有未删除点对 ...

  3. cf299C Weird Game

    Weird Game Yaroslav, Andrey and Roman can play cubes for hours and hours. But the game is for three, ...

  4. Android Studio升级到3.0,抛出Aapt2Exception异常

    android studiao错误: Android resource linking failedOutput: D:\_ASWorkSpace\phone_new\app\src\main\res ...

  5. Python 可变对象与不可变对象

    1. 不可变(immutable):int.字符串(string).float.(数值型number).元组(tuple) 可变(mutable):字典型(dictionary).列表型(list) ...

  6. 对象数据源objectdatasource的使用,类的编写实现查询增删改的方法

    原文发布时间为:2008-08-01 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...

  7. hdu 4778 Gems Fight! 状压dp

    转自wdd :http://blog.csdn.net/u010535824/article/details/38540835 题目链接:hdu 4778 状压DP 用DP[i]表示从i状态选到结束得 ...

  8. android中自定义下拉框(转)

    android自带的下拉框好用不?我觉得有时候好用,有时候难有,项目规定这样的效果,自带的控件实现不了,那么只有我们自己来老老实实滴写一个新的了,其实最基本的下拉框就像一些资料填写时,点击的时候出现在 ...

  9. (1)git

    1.创建一个版本库 #创建一个文件夹 E:\>mkdir pythonGit #进入文件夹 E:\>cd pythonGit #把此目录创建成git版本库 E:\pythonGit> ...

  10. openSUSE Leap 15.0 初始配置

    添加源: # 禁用原有软件源 sudo zypper mr -da # 添加阿里镜像源 sudo zypper ar -fc https://mirrors.aliyun.com/opensuse/d ...