noip2012提高组day2

1.同余方程

给定a,b,求满足求满足ax≡1(mod mod b)的最小x。

一开始能得到: 求 ax mod b=1 时 x的最小值 想暴力来着发现不对劲 然后趁机会推了一遍gcd,……然后听到了一个叫做扩展欧几里得的东西

扩展欧几里得:模板:

long long exgcd(long long a,long long b,long long& x,long long& y)
{
if(!b)
{
x=1;
y=0;
return a;
}
long long r=exgcd(b,a%b,y,x);
y-=a/b*x;
return r;
}

对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然
存在整数对 x,y ,使得 gcd(a,b)=ax+by。
设 a>b。
1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2,a>b>0 时
ax1+by1=gcd(a,b); a x 1 + b y 1 = g c d ( a , b ) ;
bx2+ (a mod b)y2= gcd(b,a mod b);
gcd(a,b) = gcd(b,a mod b);
则:ax1+ by1= bx2+ (a mod b)y2;
即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
说明: a-[a/b]*b即为mod运算。[a/b]代表取小于a/b的最大整数。
也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);
根据恒等定理得:x1=y2; y1=x2- [a / b] *y2;
……
最后再把问题转化成 ax+by=1 求x的最小解

#include<cstdio>
#include<algorithm>
#include<iostream> 
using namespace std;
int n,m;
void fun(int n,int m,int &x,int &y)
{
    if (!m)
      {
        x=1;
        y=0;
        return;
      }
    //cout<<m<<' '<<n%m<<' '<<' '<<y<<' '<<x<<"\n";
    fun(m,n%m,y,x);
    y-=n/m*x;
    //cout<<m<<' '<<n%m<<' '<<' '<<y<<' '<<x<<"   后面\n";
    return;
}
int main()
{
    freopen("mod.in","r",stdin);
    freopen("mod.out","w",stdout);
    scanf("%d%d",&n,&m);
    int b=m,x,y;
    fun(n,m,x,y);
    printf("%d",(x+b)%b);
    return 0;
}

2.借教室

做的时候想了很多方法 独独没有想到正解二分 可能还是我太菜的原因吧
分块可以做但是会超时
线段树则很快了
线段树
题面:给出n天,每天提供ai个教室,有m个请求,从si到ti每天借di个教室,能满足所有,输出0,不能输出-1和第一个不满足的要求编号
很明显看出来是区间修改,很自然想到线段树‘update里要记得写pushdown哦~

#include<cstdio>
#include<algorithm>
#define maxn 1110000
using namespace std;
int num[4*maxn];
long long classroom[4*maxn];
int d[maxn],b[maxn],t[maxn];
int a[maxn];
int n,m;
void update(int data){
    num[data]-=classroom[data];
    classroom[2*data]+=classroom[data];
    classroom[2*data+1]+=classroom[data];
    classroom[data]=0;
}
void add(int data,int l,int r,int ll,int rr,int x)
{
    update(data);
    if (l>rr || r<ll)return;
    if (l>=ll && rr>=r)
      {
        classroom[data]+=x;
        update(data);
        return;
      }
    int mid=(l+r)>>1;
    add(2*data,l,mid,ll,rr,x);
    add(2*data+1,mid+1,r,ll,rr,x);
    num[data]=min(num[2*data],num[2*data+1]);   
}
void build(int data,int l,int r){
    if (l==r) 
      {
        num[data]=a[l];
        return;
      }
    int mid=(l+r)>>1;
    if (l<=mid) build(2*data,l,mid);
    if (mid<r) build(2*data+1,mid+1,r);
    num[data]=min(num[2*data],num[2*data+1]);
}
int main(){
    freopen("classroom.in","r",stdin);
    freopen("classroom.out","w",stdout); 
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    for (int i=1;i<=m;i++)
        scanf("%d%d%d",&d[i],&b[i],&t[i]);
    for (int i=1;i<=m;i++){
        add(1,1,n,b[i],t[i],d[i]);
        if (num[1]<0){
            printf("-1\n%d",i);
            return 0;
        }
    }
    printf("0");
    return 0;
}

3.疫情控制

不多说,二分加贪心的图论


#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=211000;
typedef long long LL;
struct Node{
    int j,v,next;
}e[maxn];
struct NODE{
    int n1;
    LL n2;
    bool operator < (const NODE &b)const{
        return n2<b.n2;
    }
}b[maxn],c[maxn];
bool bo[maxn];
int a[maxn];
int fa[maxn][25];
LL len[maxn][25];
int id[maxn];
int n,m,cnt1,cnt2,NodeCnt=0;
void addedge(int u,int v,int w){
    int p=++NodeCnt;
    e[p].j=v;e[p].v=w;e[p].next=a[u];
    a[u]=p;
}
void dfs(int u){
    for (int p=a[u];p;p=e[p].next){
        int j=e[p].j;
        if (j!=fa[u][0]){
            fa[j][0]=u;
            len[j][0]=e[p].v;
            dfs(j);
        }
    }
}
void dfs2(int u){
    if (bo[u])return;
    bool done=true,first=true;
    for (int p=a[u];p;p=e[p].next){
        int j=e[p].j;
        if (j!=fa[u][0]){
            dfs2(j);
            done=false;
            if (!bo[j])first=false;
        }
    }
    if (u!=1 && first && !done)bo[u]=true;
}
bool check(long long time){
    memset(bo,0,sizeof(bo));cnt1=cnt2=0;
    memset(c,0,sizeof(c));
    memset(b,0,sizeof(b));
    for (int i=1;i<=m;i++){
        int up=id[i];
        LL tt=time;
        for (int j=19;j>=0;j--)
            if (fa[up][j] && tt>=len[up][j]){
                tt-=len[up][j];
                up=fa[up][j];
            }
        if (up!=1)bo[up]=true;
            else {
                c[++cnt1].n2=tt;
                up=id[i];
                for (int j=19;j>=0;j--)
                    if (fa[up][j]>1)up=fa[up][j];
                c[cnt1].n1=up;
            }
    }
    dfs2(1);
    for (int p=a[1];p;p=e[p].next){
        int j=e[p].j;
        if (!bo[j])b[++cnt2].n1=j,b[cnt2].n2=len[j][0];
    }
    if (cnt1<cnt2)return false;
    sort(c+1,c+1+cnt1);
    sort(b+1,b+1+cnt2);
    int j=1;
    b[cnt2+1].n2=0x7fffffff;
    for (int i=1;i<=cnt1;i++){
        if (!bo[c[i].n1])bo[c[i].n1]=true;
        else{
            if (c[i].n2>=b[j].n2)bo[b[j].n1]=true,j++;
        }
        while (bo[b[j].n1])j++;
    }
    return j>cnt2;
}
int main(){
    freopen("blockade.in","r",stdin);
    freopen("blockade.out","w",stdout); 
    scanf("%d",&n);
    LL r=0;
    for (int i=1;i<n;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        r+=z;
        addedge(x,y,z);
        addedge(y,x,z);
    }
    dfs(1);
    for (int j=1;j<20;j++)
        for (int i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1],len[i][j]=len[fa[i][j-1]][j-1]+len[i][j-1];
    scanf("%d",&m);
    for (int i=1;i<=m;i++)scanf("%d",&id[i]);
    LL l=0;
    while (l<r){
        LL mid=(l+r)>>1;
        if (check(mid))r=mid;
            else l=mid+1;
    }
    printf("%lld",l);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值