Orz ZZH 未来的SHTU学长
出的题目脑洞就是大
不过终于看到了一套NOIP题
【T1】 Coffee
先考虑两杯咖啡互相调配,有一个很简单的结论:对咖啡
ai
与
aj
,它们能调配出浓度在
[ai,aj]
范围内的所有咖啡
于是考虑限制,对
∀ai
,以之为左端点,右侧能与之调配的浓度最小的咖啡应满足
ak≤min(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] :
aj
≤
i
}
按照 DFS 序进行 DP
每个节点对
代码如下
#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
强行@吴克文