题解 P3277 【[SCOI2011]飞镖】

3493441984zz

2019-03-02 11:02:32

Solution

# 恶心的模拟 只是思路难想一点,其他都还好做的 本文参考了网上的题解,可能会有点雷同 ------------ # 思路: - ### 我们先不考虑取中间大小红心的情况 那么我们发现,对于在$2*k+3*k$以内的除了$2*k+3*k-1$这个数的数,我们都可以用两次投镖来得到 - ### 证明: $1.\ \ \ 2*k+3*k-1$,即:$2*(k+1)-3*(k-1)$ 但是我们只能取$[1,k]$之间的数,而$k+1$越界了,所以不能被两次投镖表示 $2.\ \ \ 2*k+3*k-2$,即:$2*(k-1)+3*k$,可以用两次投镖表示 $3.\ \ \ 2*k+3*k-3$,即:$2*k+3*(k-1)$,可以用两次投镖表示 $4.\ \ \ 2*k+3*k-4$,即:$2*(k-2)+3*k$,可以用两次投镖表示 此后每$5$个一个循环,都可以被两次投镖(一次投双倍,一次投三倍)表示出来(也有特例:$1$) 那么大于$2*k+3*k$的数就只能把两个数都取三倍了,也就是$3*a+3*b$来表示 - ### 考虑加入取红心的情况 我们列出每种情况,下文的$i$表示$[1,k]$的$1-3$倍,$|$表示最后一个选的是什么,前两个顺序随意: $1.m\ i\ |\ i$ $2.2m\ i\ |\ i$ $3.m\ m\ |\ i$ $4.m\ 2m\ |\ i$ $5.2m\ 2m\ |\ i$ $6.i\ i\ |\ 2m$ $7.m\ i\ |\ 2m$ $8.2m\ i\ |\ 2m$ $9.m\ m\ |\ 2m$ $10.m\ 2m\ |\ 2m$ $11.2m\ 2m\ |\ 2m$ 十一种情况怎么来的就不用说了吧,要记得最后一个要是双倍这个限制 那么,我们对上面十一种分一下类来讨论 $A.\ 1\ 2$ $B.\ 3\ 4\ 5$ $C.\ 6$ $D.\ 7\ 8$ $E.\ 9\ 10\ 11$ - 对于$A$类,我们把要得到的分数$x-m$或者$x-2m$ 然后,因为最后一次取一定要取双倍,所以我们用$2*a+3*b$来判断能否被表示出来,注意减完不能为$0$ - 对于$B$类,我们把$x-2m$或者$x-3m$或者$x-4m$,看看减完后是不是$2$的倍数,并且在$2k$范围之内 - 对于$C$类,我们把$x-3m$后,看看能否用$2a+3b$或者$3a+3b$表示出来 - 对于$D$类,我们把$x-3m$或者$x-4m$后,看看是否是$[1,k]$中某个数本身或者两倍或者三倍 - 对于$E$类,我们直接判断$x$是不是$4m$,$5m$,$6m$ ------------ 接下来是美滋滋的代码时间~~~ ~~~cpp #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 7 #define ll long long using namespace std; int T; ll ans,k,m,x,k1,m1,x1; ll a[N],b[N],c[N],d[N]; bool Check1() { ll kx=k; if(x-k*2<=k*3+k*2&&x-k*2!=k*3+k*2-1) return 1; while((x-kx*2)%3!=0) kx--; if((x-kx*2)<=k*6) return 1; return 0; } bool Check2(ll now) { if(now<2) return 0; if(now<=k*3+k*2&&now!=k*3+k*2-1) return 1; return 0; } bool Check3(ll now) { if(now>=0&&now%2==0&&now/2<=k) return 1; return 0; } bool Check4(ll now) { if(now<0) return 0; ll kx=k; if(now<=k*3+k*2&&now!=k*3+k*2-1) return 1; if(now%3==0&&now<=k*6) return 1; return 0; } bool Check5(ll now) { if(now<0) return 0; if(now%3==0&&now/3<=k) return 1; if(now%2==0&&now/2<=k) return 1; if(now<=k) return 1; return 0; } int main() { scanf("%d",&T); scanf("%lld%lld%lld%lld%lld",&a[1],&b[1],&c[1],&d[1],&k); scanf("%lld%lld%lld%lld%lld",&a[2],&b[2],&c[2],&d[2],&m); scanf("%lld%lld%lld%lld%lld",&a[3],&b[3],&c[3],&d[3],&x); for(int i=1;i<=T;++i) { if(Check1()) ++ans; else if(Check2(x-m)||Check2(x-2*m)) ++ans; else if(Check3(x-2*m)||Check3(x-3*m)||Check3(x-4*m)) ++ans; else if(Check4(x-2*m)) ++ans; else if(Check5(x-3*m)||Check5(x-4*m)) ++ans; else if(x==4*m||x==5*m||x==6*m) ++ans; k1=(k*k)%d[1]; k=((k1*a[1])%d[1]+(k*b[1])%d[1]+c[1])%d[1]; m1=(m*m)%d[2]; m=((m1*a[2])%d[2]+(m*b[2])%d[2]+c[2])%d[2]; x1=(x*x)%d[3]; x=((x1*a[3])%d[3]+(x*b[3])%d[3]+c[3])%d[3]; k+=20; m+=20; x+=20; } printf("%lld",ans); } ~~~