2017北京国庆刷题Day5 morning
期望得分:0+60+60=120
实际得分:0+30+60=90
令g=gcd(X11,X12,X13……)
则行列式可能为D的充要条件为g|D
1、g|D为必要条件:
由定义来算行列式的时候,每一项都要从第一行里取一个数,所以g|D
2、g|D为充分条件:
首先可以通过矩阵的初等变换,将矩阵X消成对角矩阵
其中,X11* X22 * X33* X44=D
上述矩阵等价于
把D拆为g*D/g
还原到矩阵中
即
X22=
此矩阵模拟先前初等变换即可还原为原矩阵X
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cmath> using namespace std; int gcd(int a,int b) { return !b ? a : gcd(b,a%b); } bool solve()
{
int n,m,x,y;
scanf("%d%d",&n,&m);
x=;
for (int i=;i<=n;++i)
{
scanf("%d",&y);
x=gcd(x,abs(y));
}
if (n==) return y==m;
if (!x) return !m;
return !(abs(m)%x);
} int main()
{
freopen("det.in","r",stdin);
freopen("det.out","w",stdout);
int t;
scanf("%d", &t);
while(t--)
if (solve()) printf("Y\n");
else printf("N\n");
}
每次分两半的时候,一定是奇数在左边,偶数在右边
所以用类似于线段树的思想来分治
由于每次讲将序列按奇偶下标分成两半,如果每次处理分成的那一半区间
那这个区间一定是一个等差数列,且公差为 2^d
所以
如果我们将区间离散化为1,2,3,……
那么完全可以求出区间离散化之后的答案,在回溯往上的时候每次*2(奇数*2-1),便可得到原区间的答案
例:1 2 3 4 5 6 7
第一次分治:
原左区间: 1 3 5 7 原右区间 2 4 6
离散化后区间 1 2 3 4 1 2 3
离散化后左区间 总和 1+2+3+4=10
当回溯到上一层是,实际上是(1*2-1)+(2*2-1)+(3*2-1)+(4*2-1)= 10*2-4=16
离散化后右区间 总和 1+2+3=6
当回溯到上一层是,实际上是 (1*2)+(2*2)+(3*2)=6*2=12
具体怎么求?
设当前分治到 rr,l,r,x,y
表示当前区间离散化后为[1,2,……rr],当前要求下标在本区间的[l,r]内,大小 在 本区间离散化后[x,y]之间
分四种情况:
1、对答案有贡献的数全在当前区间内,即 l=1 && r=rr
因为每次分治的区间是一个等差数列,根据求和公式,本区间的答案为(y-x+1)*(x+y)/2
2、对答案有贡献的数是当前区间的一部分且全在左区间,即r<=mid ,那就递归到左区间求解
在左区间中 ,rr变成mid,l,r 不变,x变为x/2+1,y变为(y+1)/2
3、对答案有贡献的数是当前区间的一部分且全在右区间,即l>mid,那就递归到右区间求解
在右区间中,rr变成rr-mid,l-=mid,r-=mid,x变为(x+1)/2,y变为y/2+1
4、对答案有贡献的数是当前区间的一部分且左右区间都有,左右区间都递归,再合并
这里 l,r 根上面的左右区间有所不同
左区间的r是mid,右区间的l是1
上面提到了左区间是奇数,回溯的时候 和变为*2-元素个数
所以 回溯时,除了返回 和,还要返回元素个数
用pair即可
小细节:等差数列求和的时候,(y-x+1)*(x+y)/2 乘法运算可能会爆long long
所以 判断哪个是偶数,先进行除法运算
#include<cstdio>
#include<iostream> #define mp(a,b) make_pair((a),(b)) using namespace std; typedef long long LL;
typedef pair<LL,LL>pr; LL mod; void read(LL &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} pr solve(LL rr,LL l,LL r,LL x,LL y)
{
if(x>rr || l>r) return mp(,);
if(l== && r==rr)
{
y=min(y,rr);
LL s;
if (!((x+y)&))s=(x+y>>)%mod*((y-x+)%mod)%mod;
else s=((x+y)%mod)*((y-x+>>)%mod)%mod;
return mp(s,(y-x+)%mod);
}
LL mid=rr+>>;
if(r<=mid)
{
pr res=solve(mid,l,r,(x>>)+,y+>>);
return mp(((res.first<<)-res.second)%mod,res.second);
}
if(l>mid)
{
pr res=solve(rr-mid,l-mid,r-mid,x+>>,y>>);
return mp((res.first<<)%mod,res.second);
}
pr res1=solve(mid,l,mid,(x>>)+,y+>>);
pr res2=solve(rr-mid,,r-mid,x+>>,y>>);
return mp(((res1.first<<)-res1.second+(res2.first<<))%mod,(res1.second+res2.second)%mod);
} int main()
{
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
LL n,m;
read(n); read(m); read(mod);
LL l,r,x,y;
while(m--)
{
read(l); read(r); read(x); read(y);
pr ans=solve(n,l,r,x,y);
printf("%I64d\n",(ans.first+mod)%mod);
}
}
考场 30分 莫队 ,然而枚举有60
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 100001
#define lowbit(x) x&(-x)
using namespace std;
typedef long long LL;
int a[N],n,m,mod;
int bl[N];
LL c[N],ans[N];
struct node
{
int l,r,x,y,id;
}e[N];
void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
}
void dfs(int l,int r,int k)
{
if(l==r) return;
int m=l+r>>,t=m;
dfs(l,m,k<<);
for(int i=l;i<=m;i++) if(a[i]+k<=n) a[++t]=a[i]+k;
}
bool cmp(node p,node q)
{
if(bl[p.l]!=bl[q.l]) return bl[p.l]<bl[q.l];
return p.r<q.r;
}
void add(int x,int w)
{
while(x<=n) { c[x]+=w; x+=lowbit(x); }
}
LL query(int x)
{
LL sum=;
while(x) { sum+=c[x]; x-=lowbit(x); }
return sum;
}
void update(int pos,bool ty)
{
if(ty) add(a[pos],a[pos]);
else add(a[pos],-a[pos]);
}
int main()
{
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
read(n); read(m); read(mod);
a[]=; dfs(,n,);
for(int i=;i<=m;i++)
{
read(e[i].l),read(e[i].r),read(e[i].x),read(e[i].y);
if(e[i].x>n) e[i].x=n;
if(e[i].y>n) e[i].y=n;
e[i].id=i;
}
int siz=sqrt(n);
for(int i=;i<=n;i++) bl[i]=(i-)/siz+;
sort(e+,e+m+,cmp);
int L=,R=,l,r;
for(int i=;i<=m;i++)
{
l=e[i].l; r=e[i].r;
while(L<l) update(L++,);
while(L>l) update(--L,);
while(R<r) update(++R,);
while(R>r) update(R--,);
if(e[i].x>) ans[e[i].id]=query(e[i].y)-query(e[i].x-);
else ans[e[i].id]=query(e[i].y);
}
for(int i=;i<=m;i++) printf("%I64d\n",ans[i]%mod);
}
树形DP+倍增
回想倍增法求LCA的过程
从大到小枚举k,每次跳2^k步,只要不越界就跳,最后一定能跳到LCA
因为跳的都是2的幂次步,所以每跳一步就是二进制加了一个1
先预处理fa[i][k],表示点i向上跳2^k 步的祖先节点
设 f[i][j] 表示最后一步跳了2^j步,跳到了点i的答案之和
cnt[i][j] 表示最后一步跳了2^j步,跳到了点i的方案数
因为有了倍增求lCA原理的保证,所以只需要考虑跳2的幂次步
设siz[i]表示以i为根的子树的大小
rt[i]=j 表示 当前点属于 i的子树里,以j为根节点的子树
假设dfs回溯到x,转移分两种:
1、以x为链的一个端点
枚举x向上跳2^k次,则v=fa[x][j]
那么ans+=siz[v]-siz[rt[v]] ——所有非rt[v]子树的点,与x的LCA都是v,都会有1的贡献
(类似于点分治中要去除同一子树内合法的点)
cnt[v][k]++ f[v][k]++
2、x作为倍增过程中的一个中途点
那么枚举最后一步跳了2^i 跳到了x
枚举x再往上跳2^j步,则v=fa[x][j]
那么ans+=(f[x][i]+cnt[x][i])*(siz[v]-siz[rt[v]])
f[x][i] 是原来的答案,在以v做LCA时,又会用 (siz[v]-siz[rt[v]])次
cnt[x][i] 是 要再往上跳2^j步,又有一个1的贡献
cnt[v][j]+=cnt[x][i] f[v][j]+=f[x][i]+cnt[x][i]
例:1--2--3--4 如果4到1的距离为3,二进制为11,对答案的贡献为2
回溯到4的时候,以4为端点会累积3--4 2--4
回溯到3的时候,以3为端点会累积2--3 1--3
回溯到2的时候,以2为端点会累积1--2,以2为中途点会累积1--2--3--4
(4跳2^1累积到2里,然后在枚举2为中途点时,最后一步跳了2^1到2,2再往上跳2^0)
为什么在枚举3作为中途点的时候,不枚举跳了2^0次方到了3
因为此时3不是中途点,我们是按跳2^k,k是降序跳的
个人总结:支持本题不重不漏的原理就是倍增求LCA的原理
或者是说任意数可以拆为2^k1+2^k2+2^k3…… ki 依次递减
个人AC代码
#include<cstdio>
#define N 100001 using namespace std; typedef long long LL; LL ans; int front[N],nxt[N<<],to[N<<],tot;
int fa[N][],siz[N],rt[N];
int cnt[N][],f[N][]; void add(int u,int v)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
} void dfs1(int x,int y)
{
fa[x][]=y; siz[x]=;
for(int i=;i<=;i++) fa[x][i]=fa[fa[x][i-]][i-];
for(int i=front[x];i;i=nxt[i])
if(to[i]!=y) dfs1(to[i],x),siz[x]+=siz[to[i]];
} void dfs2(int x)
{
for(int i=front[x];i;i=nxt[i])
if(to[i]!=fa[x][]) rt[x]=to[i],dfs2(to[i]);
for(int i=;i<=;i++)
{
ans+=siz[fa[x][i]]-siz[rt[fa[x][i]]];
cnt[fa[x][i]][i]++;
f[fa[x][i]][i]++;
}
for(int i=;i<=;i++)
for(int j=;j<i;j++)
{
ans+=LL(cnt[x][i]+f[x][i])*LL(siz[fa[x][j]]-siz[rt[fa[x][j]]]);
cnt[fa[x][j]][j]+=cnt[x][i];
f[fa[x][j]][j]+=f[x][i]+cnt[x][i];
}
} int main()
{
freopen("bitcount.in","r",stdin);
freopen("bitcount.out","w",stdout);
int n;
scanf("%d",&n);
int u,v;
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
}
dfs1(,);
siz[]=siz[]; nxt[]=;
dfs2();
printf("%I64d",ans);
}
自己加了中间输出辅助理解的std
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <vector> #define st first
#define nd second
using namespace std; struct edge {
int x;
int nxt;
};
typedef long long LL; const int N = 1E5 + ;
edge e[ * N];
int lca[N][], hd[N], fa[N], sons[N], nxt[N], cnt[N][], f[N][];
int n, m, x, y, l;
LL ans; void link(int x, int y) {
e[++l].x = y;
e[l].nxt = hd[x];
hd[x] = l;
} void dfs_lca(int x) {
lca[x][] = fa[x];
sons[x] = ;
for (int i = ; i <= ; ++i)
lca[x][i] = lca[lca[x][i - ]][i - ];
for (int p = hd[x]; p; p = e[p].nxt)
if (e[p].x != fa[x]) {
fa[e[p].x] = x;
dfs_lca(e[p].x);
sons[x] += sons[e[p].x];
}
} void dfs_ans(int x) {
for (int p = hd[x]; p; p = e[p].nxt)
if (e[p].x != fa[x]) nxt[x] = e[p].x, dfs_ans(e[p].x);
for (int i = ; i <= ; ++i) {
ans += sons[lca[x][i]] - sons[nxt[lca[x][i]]];
if(sons[lca[x][i]] - sons[nxt[lca[x][i]]]) printf("%d : sons[%d]-sons[%d]=%d\n",x,lca[x][i],nxt[lca[x][i]],sons[lca[x][i]] - sons[nxt[lca[x][i]]]);
cnt[lca[x][i]][i]++;
f[lca[x][i]][i]++;
}
for (int i = ; i <= ; ++i)
for (int j = ; j <= i - ; ++j) {
ans += LL(cnt[x][i] + f[x][i]) * LL(sons[lca[x][j]] - sons[nxt[lca[x][j]]]);
if(LL(cnt[x][i] + f[x][i]) * LL(sons[lca[x][j]] - sons[nxt[lca[x][j]]]))
printf("%d : cnt[%d][%d]+f[%d][%d] * sons[%d]-sons[%d] = %I64d\n",x,x,i,x,i,lca[x][j],nxt[lca[x][j]],LL(cnt[x][i] + f[x][i]) * LL(sons[lca[x][j]] - sons[nxt[lca[x][j]]]));
cnt[lca[x][j]][j] += cnt[x][i];
f[lca[x][j]][j] += f[x][i] + cnt[x][i];
}
} int main() {
//freopen("bitcount.in", "r", stdin);
//freopen("bitcount.out", "w", stdout);
scanf("%d", &n);
for (int i = ; i < n; ++i) {
scanf("%d%d", &x, &y);
link(x, y);
link(y, x);
}
dfs_lca();
sons[] = sons[];
nxt[] = ;
dfs_ans();
printf("%I64d\n", ans);
}
考场60分暴力
#include<cstdio>
#include<algorithm>
#define N 2001
using namespace std;
int front[N],to[N<<],nxt[N<<],tot;
int val[N],deep[N],id[N];
int lca[N][N],f[N][];
int n;
void add(int u,int v)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}
int cal(int x)
{
int sum=;
while(x) sum+=(x&),x>>=;
return sum;
}
void dfs(int x,int dep,int fa)
{
id[x]=++tot; deep[x]=dep;
f[x][]=fa;
for(int i=front[x];i;i=nxt[i])
if(to[i]!=fa) dfs(to[i],dep+,x);
}
int getlca(int x,int y)
{
if(id[x]<id[y]) swap(x,y);
for(int i=;i>=;i--)
if(id[f[x][i]]>id[y]) x=f[x][i];
return f[x][];
}
void prelca()
{
for(int j=;j<=;j++)
for(int i=;i<=n;i++)
f[i][j]=f[f[i][j-]][j-];
for(int i=;i<n;i++)
for(int j=i+;j<=n;j++)
lca[i][j]=getlca(i,j);
}
void solve()
{
int ans=;
for(int i=;i<n;i++)
for(int j=i+;j<=n;j++)
ans+=val[deep[i]-deep[lca[i][j]]]+val[deep[j]-deep[lca[i][j]]];
printf("%d",ans);
}
int main()
{
freopen("bitcount.in","r",stdin);
freopen("bitcount.out","w",stdout);
scanf("%d",&n);
int u,v;
for(int i=;i<n;i++) { scanf("%d%d",&u,&v); add(u,v); }
for(int i=;i<=n;i++) val[i]=cal(i);
tot=; dfs(,,);
prelca();
solve();
}
2017北京国庆刷题Day5 morning的更多相关文章
- 2017北京国庆刷题Day5 afternoon
期望得分:100+60+100=260 实际得分:0+60+40=100 设图中有m个环,每个环有si条边,有k条边不在环中 ans= (2^s1 -2)*( 2^s2 -2)* (2^s3 -2)… ...
- 2017北京国庆刷题Day1 afternoon
期望得分:100+100+100=300 实际得分:100+100+100=300 T1 一道图论好题(graph) Time Limit:1000ms Memory Limit:128MB 题目 ...
- 2017北京国庆刷题Day7 morning
期望得分:100+0+100=200 实际得分:100+20+0=120 离散化搞搞 #include<cstdio> #include<iostream> #include& ...
- 2017北京国庆刷题Day3 morning
期望得分:100+60+0=160 实际得分:100+30+0=130 考场上用的哈希 #include<cstdio> #include<cstring> #include& ...
- 2017北京国庆刷题Day2 afternoon
期望得分:100+100+50=250 实际得分:100+70+50=220 T1 最大值(max) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一 ...
- 2017北京国庆刷题Day2 morning
期望得分:100+100+40=240 实际得分:100+40+0=140 T1 一道图论神题(god) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK ...
- 2017北京国庆刷题Day4 morning
期望得分:0+40+30=70 实际得分:0+10+10=20 题目修改:只能由0变1,只能用一次操作 大模拟 #include<cstdio> #include<cstring&g ...
- 2017北京国庆刷题Day4 afternoon
期望得分:100+100+0=200 实际得分:5+0+0=5 每加入一个数,x的因数位置++ 注意:根号x枚举时,如果x是完全平方数,根号x会重复累计2次,要减去 考场上没减,5分 /(ㄒoㄒ)/~ ...
- 2017北京国庆刷题Day6 afternoon
期望得分:100+100+40=240 实际得分:100+0+40=140 二进制拆分.二进制前缀和 #include<cstdio> #include<iostream> u ...
随机推荐
- [pascal入门]数组
一.本节目标 本节我们将要讲述数组.本节目标: 一维数组 二维数组 字符数组 二.一维数组 我们通过一个案例来简单的理解数组.班主任要计算班级里面50个同学数学成绩的平均成绩,道理上讲这是一个比较简单 ...
- 操作系统cmd
实验一 命令解释程序的编写(两周内) 一.目的和要求 1. 实验目的 (1)掌握命令解释程序的原理: (2)*掌握简单的DOS调用方法: (3)掌握C语言编程初步. 2.实验要求 编写类似于DOS, ...
- 关于解决java读取excel文件遇空行抛空指针的问题 !
关于解决java读取excel文件遇空行抛空指针的问题 ! package exceRead; import java.io.File; import java.io.FileInputStream; ...
- python配置文件读取
在代码实现的过程中,我们经常选择将一些固定的参数值写入到一个单独的配置文件中.在python中读取配置文件官方提供了configParser方法. 主要有如下方法(找官文): (这家伙很懒,直接复 ...
- 微信小程序 功能函数 地图定位相对直线距离
GetDistance:function(lat1, lng1, lat2, lng2){ // console.log(lat1) var radLat1 = lat1 * Math.PI / ...
- ASP.NET前后端分离框架
- 实现全站 HTTPS ,为什么国内网站总是那么slow&&low呀!
1 https://konklone.com/post/switch-to-https-now-for-free# https://theintercept.com/2014/11/20/non-pr ...
- bug:margin塌陷
margin塌陷:两个嵌套的div,内部div的margin-top失效,内部对于外部的div并没有产生一个margin值,而是外部的div相对于上面的div产生了一个margin值. 弥补方法: 1 ...
- BZOJ4953 Wf2017Posterize(动态规划)
设f[i][j]为前i种强度选了j种且其中第i种选时前i个的最小误差.转移枚举上个选啥前缀和优化即可. #include<iostream> #include<cstdio> ...
- CF44H Phone Number
题意翻译 给你一个电话号码,根据这个号码生成一个新的号码.生成的规则就是 新号码的第一个数任意选(0-9), 然后之后的每一个新号码都按照以下规则生成: 第i个新号码=(第i-1个新号码+第i个老号码 ...