我个zz我连扩欧都不会了...
T1:
题目大意:b+ia=d+jc中,b,a,c,d都为正整数,解出i的最小正整数解,并输出b+ia,若无解输出-1.
我好菜啊我竟然把扩展欧几里得忘了,考场花了一个小时推出来的...
题目中的式子我们可以转换成ia-jc=d-b.
然后用扩欧求解就可以了.
我在想什么我竟然把c设成了负数...
考场代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ACF inline void
typedef long long LL;
LL a,b,c,d,x,y,g,l;
LL exgcd(LL a,LL b,LL &x,LL &y){
if (!b){
x=1;y=0;
return a;
}
LL g=exgcd(b,a%b,x,y),tmp=x;
x=y;y=tmp-a/b*y;
return g;
}
ACF into(){
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
}
ACF work(){
c=-c;
g=exgcd(a,c,x,y);
}
ACF outo(){
if (d==b) printf("0\n");
else if ((d-b)%g) printf("-1\n");
else {
l=c/g;
x*=(d-b)/g;y*=(d-b)/g;
if (x<0) x+=(-x)/l*l;
while (x<0) x+=l;
x-=(x/l)*l;
while (x-l>=0) x-=l;
printf("%lld\n",b+x*a);
}
}
int main(){
//freopen("run.in","r",stdin);
//freopen("run.out","w",stdout);
into();
work();
outo();
return 0;
}
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ACF inline void
typedef long long LL;
LL a,b,c,d,x,y,g,l;
LL exgcd(LL a,LL b,LL &x,LL &y){
if (!b){
x=1;y=0;
return a;
}
LL g=exgcd(b,a%b,x,y),tmp=x;
x=y;y=tmp-a/b*y;
return g;
}
ACF into(){
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
}
ACF work(){
g=exgcd(a,c,x,y);
}
ACF outo(){
if (d==b) printf("0\n");
else if ((d-b)%g) printf("-1\n");
else {
l=c/g;
x*=(d-b)/g;
x=(x%l+l)%l;
printf("%lld\n",b+x*a);
}
}
int main(){
//freopen("run.in","r",stdin);
//freopen("run.out","w",stdout);
into();
work();
outo();
return 0;
}
T2:
题目大意:有一些客人,每个客人有一个坐标(xi,yi),还有一个di表示di秒匀速走一个单位长度,现在给出每个客人的xi,yi,di,每个客人还有1的宽度,也就是说每个客人占了(xi,yi)到(xi+1,yi)这些位置.
现在,每个客人i都会到达y轴,并且若只要有一秒同时没有一个客人k在(0,yk)满足yk<yi,则会被记录下来,求记录下来的客人有几个.
注:n<=50000 1<=di<=10^5.
这道题好像很难,考场上暴力写不出来,果断报复社会(交了一个死循环卡时)...
正解的思路就是利用所有客人的两个事件点——一个进入y轴,一个走出y轴,先提前算出来.
然后按照事件点的时间为第一关键字,y轴位置为第二关键字从小到大排序.
之后建立一个set,表示这个点当前是否位于0的位置.
然后枚举一遍所有事件点,直接对这个set进行操作即可.
存下来一个人是否出现过也用一个set来实现就行了.
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ACF inline void
typedef long long LL;
const int N=50000;
pair< int , int >e[N*2+2];
int n,top;
set< int > s,ss;
ACF into(){
scanf("%d",&n);
int x,y,d;
for (int i=1;i<=n;i++){
scanf("%d%d%d",&x,&y,&d);
x*=-d;
e[++top].first=x-d;e[top].second=y;
e[++top].first=x;e[top].second=-y;
}
}
ACF work(){
sort(e+1,e+1+top);
for (int i=1;i<=top;){
int j=i;
for (;j<=top&&e[i].first==e[j].first;j++)
if (e[j].second>0) s.insert(e[j].second);
else s.erase(-e[j].second);
if (!s.empty()) ss.insert(*s.begin());
i=j;
}
}
ACF outo(){
printf("%d\n",ss.size());
}
int main(){
//freopen("watch.in","r",stdin);
//freopen("watch.out","w",stdout);
into();
work();
outo();
return 0;
}
T3:
题目大意:现在有一棵树,树上有n个节点和m条链可以选择占领,占领的每条链之间不能重合,要求得分最大.
注:1<=n,m<=10^5.
这道题本来在考场上写了40分链的数据,然后挂掉了.
现在也不知道是什么错误,下面是错误代码:
#include<bits/stdc++.h>
using namespace std;
#define ACF inline void
const int N=100000;
const int INF=1000000000;
struct seg{
int l,r,v;
}e[N+1];
int n,m,f[N+1];
ACF into(){
scanf("%d%d",&n,&m);
int x,y;
for (int i=1;i<n;i++)
scanf("%d%d",&x,&y);
for (int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].l,&e[i].r,&e[i].v);
}
bool cmp(seg a,seg b){
return a.r<b.r;
}
ACF work(){
sort(e+1,e+1+m,cmp);
int j=1;
for (int i=1;i<=n;i++){
f[i]=f[i-1];
for (;e[j].r==i;j++)
f[i]=max(f[i],f[e[j].l-1]+e[j].v);
}
}
ACF outo(){
printf("%d\n",f[n]);
}
int main(){
//freopen("occupy.in","r",stdin);
//freopen("occupy.out","w",stdout);
into();
work();
outo();
return 0;
}
正解是用f[i][0]表示以i为根的子树不占领根的最优解,f[i][1]是占领的最优解.
后者较为简单,直接统计所有儿子的结果就可以了.
前者则需要枚举链,枚举的是两端的lca是当前结点i的链.
然后dp方程就是,.
其中x表示i不在链上的儿子,y表示i在链上的儿子.
然后在各种用树状数组维护,具体我也不太清楚,因为不大会这道题.
题目代码也写不出来...
所以这里就不发代码啦.