bzoj 5418
这是拓展crt的典型应用
在你开始做之前,我一定要告诉你一件事情:虽然这道题看着和拓展crt模板很像,但他俩是有巨大的区别的!不要直接把板子改吧改吧扔上去!
题目模型:求解模线性方程组
其中p1,p2...pn不一定互质
第一眼:拓展crt板子题!
第二眼:等等...好像不太对
第三眼:WTF!系数哪来的!
我们知道,拓展crt的模板只能解决x系数为1的情况,而系数不为1的是很难做的!
什么?直接乘逆元变成1?
逆元不存在呢?
我们稍微做一点推导:
首先,我们解一下方程
设这个方程的一个解是x0(这是可以使用拓展gcd求解的)
那么这个方程的通解应该是,k∈Z
那么这个通解等价于方程的解
发现什么了吗?
是的!我们证明了方程与方程等价,这样就消掉了前面那个方程的系数!
所以,原方程组等价于这样:
这就很好了,我们使用正常的拓展crt解之即可
最后有几个细节问题:
①:对于ai>pi的情况,题目中给出的约束条件是pi=1,这样虽然拓展crt处理不了,但是我们可以应用特判过掉(p=1啊,多显然)
②:对于所有ai=pi的情况(即任一ai都=pi),只有当对应的攻击力是pi的倍数的时候才有解,否则无解,这个也要特判(有解也要特判,否则拓展crt解的结果会是0)
③:对于部分ai=pi的情况,如果对应攻击力不是pi的倍数则无解,但如果是pi的倍数,那么这个方程基本没用,可以替换成之类的形式
④:题目中运算很大,对于带取模的乘法需要快速加优化!同时所有数据类型建议使用long long以免挂掉
(求前驱那里本人使用的是treap,表示很好用)
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
#define ls tree[rt].lson
#define rs tree[rt].rson
#define INF 0x3f3f3f3f
using namespace std;
ll n,m;
ll a[];
ll b[];
ll life[];
ll acc[];
ll p[];
ll s[];
int cyt=;
int rot=;
struct Treap
{
int lson;
int rson;
int huge;
int same;
ll val;
int rank;
}tree[];
void update(int rt)
{
tree[rt].huge=tree[ls].huge+tree[rs].huge+tree[rt].same;
}
void lturn(int &rt)
{
int temp=rs;
rs=tree[rs].lson;
tree[temp].lson=rt;
tree[rt].huge=tree[temp].huge;
update(temp);
rt=temp;
}
void rturn(int &rt)
{
int temp=ls;
ls=tree[ls].rson;
tree[temp].rson=rt;
tree[rt].huge=tree[temp].huge;
update(temp);
rt=temp;
}
void ins(int &rt,ll v)
{
if(!rt)
{
rt=++cyt;
tree[rt].huge=;
tree[rt].same=;
tree[rt].val=v;
tree[rt].rank=rand();
return;
}
if(v==tree[rt].val)
{
tree[rt].huge++;
tree[rt].same++;
return;
}else if(tree[rt].val>v)
{
ins(ls,v);
if(tree[ls].rank<tree[rt].rank)
{
rturn(rt);
}
}else
{
ins(rs,v);
if(tree[rs].rank<tree[rt].rank)
{
lturn(rt);
}
}
}
void del(int &rt,ll v)
{
if(!rt)
{
return;
}
if(tree[rt].val==v)
{
if(tree[rt].same>)
{
tree[rt].huge--;
tree[rt].same--;
return;
}else if(ls*rs==)
{
rt=ls+rs;
return;
}else
{
if(tree[ls].rank<tree[rs].rank)
{
rturn(rt);
del(rt,v);
}else
{
lturn(rt);
del(rt,v);
}
}
}
tree[rt].huge--;
if(tree[rt].val>v)
{
del(ls,v);
}else
{
del(rs,v);
}
update(rt);
}
void query_pro(int rt,ll v,int typ)
{
if(!rt)
{
return;
}
if(tree[rt].val==v)
{
acc[typ]=v;
return;
}else if(tree[rt].val<v)
{
acc[typ]=tree[rt].val;
query_pro(rs,v,typ);
}else
{
query_pro(ls,v,typ);
}
}
int query_min(int rt)
{
if(ls&&tree[ls].val!=-INF)
{
return query_min(ls);
}else if(tree[rt].val!=-INF)
{
return tree[rt].val;
}else
{
return query_min(rs);
}
}
ll pow_add(ll x,ll y,ll mod)
{
ll ans=;
while(y)
{
if(y%)
{
ans+=x;
ans%=mod;
}
y/=;
x+=x;
x%=mod;
}
return ans;
}
ll gcd(ll x,ll y)
{
if(y==)
{
return x;
}
return gcd(y,x%y);
}
void ex_gcd(ll a,ll b,ll &x,ll &y)
{
if(b==)
{
x=;
y=;
return;
}
ex_gcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-(a/b)*x;
}
bool makeit()
{
for(int i=;i<=n;i++)
{
if(acc[i]%p[i]==)
{
if(p[i]==life[i])
{
a[i]=;
b[i]=;
continue;
}else
{
printf("-1\n");
return ;
}
}
ll x,y;
ll r=gcd(acc[i],p[i]);
if(life[i]%r)
{
printf("-1\n");
exit();
}
acc[i]/=r;
ll temp=life[i]/r;
ll tt=p[i]/r;
ex_gcd(acc[i],tt,x,y);
x=(pow_add(x,temp,tt)+tt)%tt;
b[i]=x;
a[i]=tt;
}
return ;
}
ll ex_crt()
{
ll M0=a[];
ll ans=b[];
for(int i=;i<=n;i++)
{
ll r=gcd(M0,a[i]);
ll bb=((b[i]-ans)%a[i]+a[i])%a[i];
if(bb%r)
{
return -;
}
bb/=r;
ll M=M0/r;
ll aa=a[i]/r;
ll x,y;
ex_gcd(M,aa,x,y);
x=pow_add(x,bb,aa);
ans+=x*M0;
M0*=aa;
ans=(ans%M0+M0)%M0;
}
return (ans%M0+M0)%M0;
}
ll T;
int main()
{
scanf("%lld",&T);
while(T--)
{
memset(tree,,sizeof(tree));
rot=;
cyt=;
ins(rot,-INF);
scanf("%lld%lld",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%lld",&life[i]);//龙的生命力
}
bool flag=,flag1=;
for(int i=;i<=n;i++)
{
scanf("%lld",&p[i]);//龙的恢复力
if(life[i]>p[i])
{
flag=;
}
if(life[i]!=p[i])
{
flag1=;
}
}
for(int i=;i<=n;i++)
{
scanf("%lld",&s[i]);
}
for(int i=;i<=m;i++)
{
ll x;
scanf("%lld",&x);
ins(rot,x);
}
for(int i=;i<=n;i++)
{
acc[i]=;
query_pro(rot,life[i],i);
if(acc[i]==-INF)
{
acc[i]=query_min(rot);
}
del(rot,acc[i]);
ins(rot,s[i]);
}
if(!flag1)
{
bool flag2=;
ll ans=;
for(int i=;i<=n;i++)
{
if(life[i]%acc[i]!=)
{
printf("-1\n");
flag2=;
}else
{
ll cd=gcd(ans,life[i]/acc[i]);
ans*=life[i]/acc[i]/cd;
}
}
if(!flag2)
{
printf("%lld\n",ans);
}
continue;
}
if(flag)
{
ll temp=;
for(int i=;i<=n;i++)
{
if(life[i]%acc[i]!=)
{
temp=max(temp,life[i]/acc[i]+);
}else
{
temp=max(temp,life[i]/acc[i]);
}
}
printf("%lld\n",temp);
continue;
}
if(makeit())
{
continue;
}
printf("%lld\n",ex_crt());
}
return ;
}
bzoj 5418的更多相关文章
- [LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士
[LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士 题意 题面好啰嗦啊直接粘LOJ题面好了 小 D 最近在网上发现了一款小游戏.游戏的规则如下: 游戏的目标是按照 ...
- 【刷题】BZOJ 5418 [Noi2018]屠龙勇士
www.lydsy.com/JudgeOnline/upload/noi2018day2.pdf Solution 将攻击的式子列出来,\(atk \times x-p \times y=a_i\) ...
- BZOJ 5418: [Noi2018]屠龙勇士 EXCRT+multiset
题解:求解形如 $A[i]ans\equiv b[i](mod$ $p[i])$ 的 $x$ 的最小正整数解. 考虑只有一个等式,那么可以直接化成 $exgcd$ 的形式:$A[i]ans+p[i]y ...
- BZOJ 2127: happiness [最小割]
2127: happiness Time Limit: 51 Sec Memory Limit: 259 MBSubmit: 1815 Solved: 878[Submit][Status][Di ...
- BZOJ 3275: Number
3275: Number Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 874 Solved: 371[Submit][Status][Discus ...
- BZOJ 2879: [Noi2012]美食节
2879: [Noi2012]美食节 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1834 Solved: 969[Submit][Status] ...
- bzoj 4610 Ceiling Functi
bzoj 4610 Ceiling Functi Description bzoj上的描述有问题 给出\(n\)个长度为\(k\)的数列,将每个数列构成一个二叉搜索树,问有多少颗形态不同的树. Inp ...
- BZOJ 题目整理
bzoj 500题纪念 总结一发题目吧,挑几道题整理一下,(方便拖板子) 1039:每条线段与前一条线段之间的长度的比例和夹角不会因平移.旋转.放缩而改变,所以将每条轨迹改为比例和夹角的序列,复制一份 ...
- 【sdoi2013】森林 BZOJ 3123
Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负整数 ...
随机推荐
- JavaWeb(一)Servlet
一.Servlet简介 Servlet 是J2EE的一个规范,为Java提供统一的web应用规范. 广义的Servlet 是指实现了servlet的类 二.Servlet工作原理 1.原理: 一个ht ...
- G - Intersecting Rectangles Kattis - intersectingrectangles (扫描线)(判断多个矩形相交)
题目链接: G - Intersecting Rectangles Kattis - intersectingrectangles 题目大意:给你n个矩形,每一个矩形给你这个矩形的左下角的坐标和右上角 ...
- 小程序学习(冒泡,快速创建文件,以及tarbar)
1.关于小程序的事件冒泡机制 例如: <view catchtap="opp"> <text>当前内容</text> </view> ...
- const关键字的作用
1.防止被修饰的成员的内容被改变. 2.修饰类的成员函数时,表示其为一个常函数,意味着成员函数将不能修改类成员变量的值. 3.在函数声明时修饰参数,表示在函数访问时参数(包括指针和实参)的值不会发生变 ...
- understand 在windows 以及 unbuntu 下的安装
1.win7 64位下安装 1)下载Understand.4.0.908.x64.rar. 2)解压之,直接运行里面的Understand-4.0.908-Windows-64bit.exe. 3)选 ...
- SpringBoot的Session并发控制
⒈是什么? 即控制业务系统中一个用户只能有一个Session ⒉解决方案 1.当这个用户在其它地方登录的时候,把之前的Session失效掉. package cn.coreqi.security.co ...
- android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论【转】
转自:https://www.cnblogs.com/deman/p/5584198.html 阅读目录 1.OpenGL & OpenGL ES 2.Android的硬件接口HAL 3.An ...
- Windowns下使用SecuretCRT编写脚本增加高亮
作者:邓聪聪 secureCRT设置高亮1)修改环境变量:export TERM=xterm-color 2)增加VIM高亮:vim ~/.vimrc set syntax=on colorsch ...
- C++怎么实现线程安全
muduo库学习笔记1-C++多线程系统编程 网上都说这本书很适合初学者入门学习, 我今天开始准备从头再来; 第一章线程安全的对象管理 对象的生与死不能由对象自身拥有的mutex(互斥器)来保护; 如 ...
- jvm 监控工具
背景 不懂jvm监控工具好意思说自己搞java的吗.其实搞了十多年的人我都见过不懂得,不懂不要紧,老实工作就行啊.这就是属于非技术的话题了,实在不知从何说起.还是赶紧学习下吧,可以去装了.我认真学习后 ...