20150810解題報告

Orz ZZH 未來的SHTU學長
出的題目腦洞就是大
不過終於看到了一套NOIP題

【T1】 Coffee

先考慮兩杯咖啡互相調配,有一個很簡單的結論:對咖啡aiaj ,它們能調配出濃度在[ai,aj] 範圍內的所有咖啡
於是考慮限制,對ai ,以之爲左端點,右側能與之調配的濃度最小的咖啡應滿足akmin(rj:lj>ai)
接下來討論有多杯咖啡的情況,設ai 形成[li,ri] 的可行範圍,aj 形成[lj,rj] 的可行範圍,易知不存在i,j 使得lj<ri 。因爲如果存在,ai 就可以與aj 配對,這與題設是矛盾的。
所以,最終形成的可行範圍沒有交集,即形成若干個不相交的區間
代碼如下

#include <bits/stdc++.h>
using namespace std;
#define rep(i,s,t) for (int i=(s);i<=(t);i++)
#define per(i,s,t) for (int i=(s);i>=(t);i--)
#define REP(i,n) rep(i,0,(n)-1)
#define PER(i,n) per(i,(n)-1,0)
typedef long long LL;

const string filename="coffee";
inline void setIO() {
    freopen((filename+".in").c_str(),"r",stdin);
    freopen((filename+".out").c_str(),"w",stdout);
}

const int W=1000000000;
const int N=333333;

inline void rd(int &x) {
  double d; scanf("%lf",&d);
  x=d*W+0.5;
}

int n,m,Q,a[N],q[N],rl[N],r[N];
pair<int,int> lim[N],query[N];
bool ans[N];

inline void cmin(int &a,int b) { if (a>b) a=b; }

int main() {
  setIO();
  scanf("%d",&n); REP(i,n) rd(a[i]);
  scanf("%d",&m); REP(i,m) { rd(lim[i].first); rd(lim[i].second); }

  sort(lim,lim+m); sort(a,a+n); lim[m]=make_pair(W,W-1);
  int j=m,currl=W;
  PER(i,n) {
    for (;j&&lim[j-1].first>a[i];cmin(currl,lim[--j].second+1));
    rl[i]=currl;
  }

  j=n-1;
  PER(i,n) {
    for (;j&&a[j]>rl[i];j--);
    r[i]=j;
  }

  scanf("%d",&Q); REP(i,Q) { rd(query[i].first); query[i].second=i; }
  sort(query,query+Q);
  j=-1;
  REP(i,Q) {
    for (;j<n-1&&a[j+1]<=query[i].first;j++);
    ans[query[i].second]=~j&&a[r[j]]>=query[i].first;
  }

  REP(i,Q) puts(ans[i]?"YES":"NO");

  return 0;
}

【T2】 Cicada

就是在樹上打導彈
維護 gi 表示 max{f[j] : aji }
按照 DFS 序進行 DP
每個節點對 g 進行修改前將 (i,gi) 入棧,回溯時彈棧恢復
代碼如下

#include <bits/stdc++.h>
using namespace std;
#define rep(i,s,t) for (int i=(s);i<=(t);i++)
#define per(i,s,t) for (int i=(s);i>=(t);i--)
#define REP(i,n) rep(i,0,(n)-1)
#define PER(i,n) per(i,(n)-1,0)
typedef long long LL;

const string filename="cicada";
inline void setIO() {
  freopen((filename+".in").c_str(),"r",stdin);
  freopen((filename+".out").c_str(),"w",stdout);
}

char buf[10<<20],*ch;
inline void rd(int &x) {
  int k=1;
  for (;!isdigit(*ch)&&*ch!='-';ch++); 
  if (*ch!='-') x=*ch++-'0';
  else { k=-1; x=0; ch++; }
  for (;isdigit(*ch);x=x*10+k*(*ch++-'0')); 
}

const int N=333333;
int n,p[N],a[N],pool[N],cp;
int adj[N],v[N],nxt[N],e;

inline void ins(int u0,int v0) {
  nxt[e]=adj[u0]; v[e]=v0; adj[u0]=e++;
}

int ans=0,d[N],cu;
pair<int,int> logu[N*20];
inline int lowbit(int x) { return x&(-x); }
inline void update(int p,int x) {
  for (++p;p<=cp&&x>d[p];logu[cu++]=make_pair(p,d[p]),d[p]=x,p+=lowbit(p));
}
inline int query(int p) {
  int ret=0;
  for (++p;p;ret=max(ret,d[p]),p-=lowbit(p));
  return ret;
}
inline void recover(int cu0) {
  for (;cu>cu0;--cu,d[logu[cu].first]=logu[cu].second);
}

void solve(int u) {
  int cu0=cu,x=lower_bound(pool,pool+cp,a[u])-pool,cur=query(x)+1;
  if (cur>ans) ans=cur; update(x,cur);
  for (int e=adj[u];~e;e=nxt[e])
    solve(v[e]);
  recover(cu0);
}

int main() {
  setIO();
  fread(buf,sizeof(buf),sizeof(char),stdin); ch=buf;
  memset(adj,-1,sizeof(adj));
  rd(n);
  rep(i,2,n) { rd(p[i]); ins(p[i],i); }
  rep(i,1,n) { rd(a[i]); pool[cp++]=a[i]; }
  sort(pool,pool+cp); cp=unique(pool,pool+cp)-pool;

  solve(1);
  printf("%d\n",ans);

  return 0;
}

【T3】 Poker

顯示出題人腦洞的bug來了
感覺做法很多,最後也的確很多,大部分人都差不多A了
我的想法跟std是差不多的,將圖形中有1的部分截出一個正方形,數每一個區域的面積
2*2的方格不能區分梅花和黑桃
3*3的方格就可以了
還有一些算法比如從上往下掃描找坑,或者判對稱軸之類,也都挺妙的
代碼如下

#include <bits/stdc++.h>
using namespace std;
#define rep(i,s,t) for (int i=(s);i<=(t);i++)
#define per(i,s,t) for (int i=(s);i>=(t);i--)
#define REP(i,n) rep(i,0,(n)-1)
#define PER(i,n) per(i,(n)-1,0)
typedef long long LL;

const string filename="poker";
inline void setIO() {
  freopen((filename+".in").c_str(),"r",stdin);
  freopen((filename+".out").c_str(),"w",stdout);
}

const int N=555;
int n,m;
double p;
int M[N][N];
double D[9];
string ans[4]={"Diamond","Spade","Club","Heart"};
const double V[4][9]={
  {0.042806683,0.164824870,0.041462368,0.161262258,0.169118495,0.155786268,0.051695890,0.169020012,0.044023156},
  {0.030754534,0.165555271,0.105244778,0.146315997,0.161825522,0.093205983,0.029695593,0.163861139,0.103541181},
  {0.034271952,0.121534851,0.115068638,0.178774288,0.161094615,0.105814550,0.039881434,0.125638425,0.117921249},
  {0.168051783,0.119391638,0.017106455,0.118067733,0.143033298,0.121071201,0.169367537,0.123633965,0.020276389}
};

int OM[N][N];
inline void gauss() {
  memcpy(OM,M,sizeof(M));
  rep(i,1,n) {
    rep(j,1,m) {
      int cnt=0;
      rep(dx,-1,1) rep(dy,-1,1) cnt+=OM[i+dx][j+dy];
      M[i][j]=cnt>=3;
    }
  }
}

int main() {
  setIO();
  scanf("%d%d%lf",&n,&m,&p);
  rep(i,1,n) rep(j,1,m) scanf("%d",&M[i][j]);

  int x0=0,y0=0,tot=0,x1=n,x2=1,y1=m,y2=1;
  rep(i,1,n) rep(j,1,n) if (M[i][j]) {
    if (i<x1) x1=i; if (i>x2) x2=i;
    if (j<y1) y1=j; if (j>y2) y2=j;
    x0+=i; y0+=j; tot++;
  }

  int dx[4]={x1-1,(x2-x1)/3+x1,(x2-x1)/3*2+x1,x2};
  int dy[4]={y1-1,(y2-y1)/3+y1,(y2-y1)/3*2+y1,y2};
  REP(k,9) {
    rep(i,dx[k%3]+1,dx[k%3+1])
      rep(j,dy[k/3]+1,dy[k/3+1])
      D[k]+=M[i][j];
    D[k]/=tot;
  }

  int choice=0; double diff=1e9;
  REP(i,4) {
    double cur=0;
    REP(j,9) cur+=(D[j]-V[i][j])*(D[j]-V[i][j]);
    if (cur<diff) { diff=cur; choice=i; }
  }

  cout<<ans[choice]<<endl;

  return 0;
}

尾聲

所以今天的題就這麼寫完了,貌似比金大師那套題寫的更好把
果然有solution可以看就會說人話了
要看更詳細的部分題解就戳這裏去看題解吧
我覺得是沒什麼卵用
poker那道題再次凸顯了智障數學巨人的本色【不要問我爲什麼】
p.s 神海龍王 & 水葫蘆娃 都是Shlw
強行@吳克文

End.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章