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]勾股定理的更多相关文章
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- bzoj-2338 2338: [HNOI2011]数矩形(计算几何)
题目链接: 2338: [HNOI2011]数矩形 Time Limit: 20 Sec Memory Limit: 128 MB Description Input Output 题意: 思路 ...
- JavaScript数学揭密之函数与勾股定理
一.函数 function show(n){ return n*2; } alert( show(2) ); alert( show(3) ); alert( show(4) ); 二.勾股定理 1. ...
- 【概率DP/高斯消元】BZOJ 2337:[HNOI2011]XOR和路径
2337: [HNOI2011]XOR和路径 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 682 Solved: 384[Submit][Stat ...
- bzoj2326: [HNOI2011]数学作业
矩阵快速幂,分1-9,10-99...看黄学长的代码理解...然而他直接把答案保存在最后一行(没有说明...好吧应该是我智障这都不知道... #include<cstdio> #inclu ...
- BZOJ2337: [HNOI2011]XOR和路径
题解: 异或操作是每一位独立的,所以我们可以考虑每一位分开做. 假设当前正在处理第k位 那令f[i]表示从i到n 为1的概率.因为不是有向无环图(绿豆蛙的归宿),所以我们要用到高斯消元. 若有边i-& ...
- Mac Dock 效果及原理(勾股定理)
这个是苹果机上的 Dock 效果,Windows 上也有一款专门的模拟软件——RocketDock. 代码如下: <!doctype html> <html> <head ...
- BZOJ 2329: [HNOI2011]括号修复( splay )
把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, ...
- BZOJ 2337: [HNOI2011]XOR和路径( 高斯消元 )
一位一位考虑异或结果, f(x)表示x->n异或值为1的概率, 列出式子然后高斯消元就行了 --------------------------------------------------- ...
随机推荐
- 【bzoj4197】[Noi2015]寿司晚宴 分解质因数+状态压缩dp
题目描述 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了 n−1 种不同的寿司,编号 ...
- BZOJ 4259 残缺的字符串 ——FFT
[题目分析] 同bzoj4503. 只是精度比较卡,需要试一试才能行O(∩_∩)O 用过long double,也加过0.4.最后发现判断的时候改成0.4就可以了 [代码] #include < ...
- [luoguP3668] [USACO17OPEN]Modern Art 2 现代艺术2(栈)
传送门 还是一个字——栈 然后加一大堆特判 至少我是这么做的 我的代码 #include <cstdio> #include <iostream> #define N 1000 ...
- Codeforces787D - Legacy
Description \(n(n\leq10^5)\)个点构成的有向图,有\(m(m\leq10^5)\)条连通信息,信息有三种: 1 u v w,表示存在一条边权为\(w\)的有向边\((u,v) ...
- Codeforces 894.A QAQ
A. QAQ time limit per test 1 second memory limit per test 256 megabytes input standard input output ...
- OpenJ_Bailian3375
Farmer John has decided to reward his cows for their hard work by taking them on a tour of the big c ...
- 【POJ3415】Common Substrings(后缀数组,单调栈)
题意: n<=1e5 思路: 我的做法和题解有些不同 题解是维护A的单调栈算B的贡献,反过来再做一次 我是去掉起始位置不同这个限制条件先算总方案数,再把两个串内部不合法的方案数减去 式子展开之后 ...
- html的常见meta标签信息
设置页面不缓存<meta http-equiv="pragma" content="no-cache"><meta http-equiv=&q ...
- postman 快捷方式--启动图标
下载,解压,安装,(此安装位置在/opt) 1.创建全局变量,也就是在任何地方都可以执行postman,不用去到安装目录,执行 : sudo ln -s /opt/postman/Postman /u ...
- Codeforces 655E Beautiful Subarrays【01trie树】
题目链接: http://codeforces.com/contest/665/problem/E 题意: 求异或值大于给定K的区间个数. 分析: 首先我们可以得到区间前缀的异或值. 这样我们将这个前 ...