1. 程式人生 > >NOIP 2012 Day2

NOIP 2012 Day2

為什麽 amp www ring pri tdi 同余 標記 http

tags:

  • 擴展歐幾裏得
  • 二分答案
  • 查分
  • 倍增
  • 二分答案
  • 貪心
  • NOIP
    categories:
  • 信息學競賽
  • 總結

同余方程
借教室
疫情控制

同余方程

Solution

  首先同余式可以轉化為等式.
\[ax\equiv 1\mod b\Leftrightarrow ax+by=1\]
  根據擴展歐幾裏得定理, 對於式
\[ax+by=k(a,b),k\in \mathbf{R}\]一定存在整數解.然而題面說一定存在解, 也就是說\((a,b)=1\), 然後就可以利用擴展歐幾裏得遞歸求得一組解.利用這組解加上取模, 就可以獲得最小整數解.

Code

#include<cstdio>
void exgcd(int a,int b,int &x,int &y){ if(!b){ x=1,y=0;return ; } exgcd(b,a%b,y,x); y-=x*(a/b); } int main(){ int a,b,x,y; scanf("%d%d",&a,&b); exgcd(a,b,x,y); printf("%d",(x%b+b)%b); return 0; }

借教室

Solution

  可以發現近些年 NOIP 總是出二分答案

的題.
  其實就是給出一些操作, 每次對一定區間減去一個數, 求在哪次操作之後產生了負數.然而可以用線段樹強行做, 也可以用一些巧妙一點的辦法.

  • 線段樹, 只需要有區間加操作和查詢區間最小值操作, 一般線段樹可以拿到95分, 還可以用可以各種卡常技巧, zkw線段樹或者是標記永久化來加快.
  • 二分一個值\(\text{T}\), 表示前\(\text{T}\)次借教室後會不會出現不合法情況(即某天教室只剩下負數間), 然後用差分借完\(T\)次教室後每一天剩下的教室數.這個一般情況是不會被卡的.註意對於答案的記錄.

Code

#include<cstring>
#include<cstdio>
#define N 1000055 #define inf 0x3f3f3f3f #define int long long struct Node{ int l,r,s; void init(){scanf("%lld%lld%lld",&s,&l,&r);} }s[N]; int n,m,d[N]; int qi[N]; int ans; int min(int a,int b){ return a<b?a:b; } bool check(int tim){ qi[0]=0; for(int i=1;i<=n;++i) qi[i]=d[i]-d[i-1]; for(int i=1;i<=tim;++i) qi[s[i].l]-=s[i].s,qi[s[i].r+1]+=s[i].s; int he=0; for(int i=1;i<=n+1;++i){he+=qi[i];if(he<0){ans=min(ans,tim);return false;}} return true; } main(){ ans=inf; scanf("%lld%lld",&n,&m); for(int i=1;i<=n;++i) scanf("%lld",&d[i]); for(int i=1;i<=m;++i) s[i].init(); int l=1,r=m,mid; while(l<=r){ mid=(l+r)>>1; if(!check(mid)) r=mid-1; else l=mid+1; } if(l>=m) printf("0"); else printf("-1\n%lld",ans); return 0; }

疫情控制

  並不是很明白為什麽一天會出兩道二分答案的題目...
  首先二分一個值\(\text{T}\), 表示在\(\text{T}\)時刻內能封鎖這棵樹
  還是有一個很重要的貪心策略, 就是一個點在到達根節點之前總是越往上走越好.然後根據倍增確定出每個點在給定時間\(\text{T}\)所到達的最高點(根節點為終點). 必然有一些點到達不了根節點, 那麽就讓它來控制這個點; 必然有在不同時間到達根節點的點, 這些點可以去控制根節點的不同沒被控制的子樹; 所以最後找出所有沒有被控制的樹點能到達根節點的軍隊進行貪心即可.
  細節太多了, 很討厭吶.

NOIP 2012 Day2