7.22 考试

期望得分:(60+?)+10+60

实际得分:60+0+50

A. 方程的解

这是一道特判题。

很容易想到60分的解法(其实就是qj)。

不考虑ZenMeZheMeDuo

测试点分治:

对于a==b==1  c-1

对于a+b==c  1

对于a b c<=1000  直接暴枚x,然后代入求y验证

对于接下来的分,就要用到只有一堆特判和exgcd了。

其实我打了exgcd,说下错因: 我没弄清exgcd求得是怎样一组特解,于是我当时手模了几个点,发现当a>b时可以求出y的最大值(然而只是巧合),然后就没了。

exgcd求得是一组解,但不‘特’,所以要求出最小非负整数解的话,假设d是gcd(a,b),x是求出的解,x0是所求最小非负整数解,则x0=(x%(b/d)+(b/d))%(b/d);

然后x0不一定是解题中需要的最小正整数解x1,判下若x0==0 则x1+=(b/d);

代入x1可以算出y1(y最大值)

同理(解的间隔为a/d)我们可以算出y2(y最小值)。然后用pa大神的方法,判下y1<y2无解。若有解可知$ans= \lfloor (y1-y2)/(a/d) \rfloor $

之后是极其恶心的特判,详细的还是看代码吧(没人看的别做梦了,只有你自己!),懒得写了额。

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<algorithm>
  4 #define ll long long
  5 #define reg register
  6 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
  7 using namespace std;
  8 inline ll read();
  9 const ll ma=65535;
 10 ll a,b,c;
 11 void sol_1()        //a==b==1
 12 {
 13     if(c<=1) puts("0");
 14     else if(c-1<=ma) printf("%lld\n",c-1);
 15     else puts("ZenMeZheMeDuo");
 16 }
 17 void sol_2()        //<=10^3
 18 {
 19     ll ans=0;
 20     F(x,1,1000)
 21     {
 22         if(a*x>=c) break;
 23         ll t=c-a*x;
 24         if(t%b) continue;
 25         ++ans;
 26     }
 27     if(ans<=ma) printf("%lld\n",ans);
 28     else puts("ZenMeZheMeDuo");
 29 }
 30 void sol_3()        //a+b==c
 31 {
 32     puts("1");
 33 }
 34 ll x,y;
 35 ll exgcd(ll a,ll b)
 36 {
 37     if(!b)
 38     {
 39         x=1;
 40         y=0;
 41         return a;
 42     }
 43     ll g=exgcd(b,a%b);
 44     ll tx=x;
 45     x=y;
 46     y=tx-a/b*y;
 47     return g;
 48 }
 49 void sol_4()
 50 {
 51     ll d=exgcd(a,b);
 52     if(c%d)
 53     {
 54         puts("0");
 55         return;
 56     }
 57     x*=(c/d);
 58     y*=(c/d);
 59     if((a>0&&b<0)||(a<0&&b>0))
 60     {
 61         puts("ZenMeZheMeDuo");
 62         return;
 63     }
 64     ll x1=(x%(b/d)+(b/d))%(b/d);
 65     ll y1=(c-a*x1)/b;
 66     if(x1==0)
 67     {
 68         x1+=(b/d); y1-=(a/d);
 69     }
 70     /*if(y1<=0)
 71     {
 72         puts("0");
 73         return;
 74     }*/
 75     ll y2=(y%(a/d)+(a/d))%(a/d);
 76     ll x2=(c-b*y2)/a;
 77     if(y2==0)
 78     {
 79         x2-=(b/d); y2+=(a/d);
 80     }
 81     /*if(x2<=0)
 82     {
 83         puts("0");
 84         return;
 85     }*/
 86     if(y1-y2<0)
 87     {
 88         puts("0");
 89         return;
 90     }
 91     ll ans=(y1-y2)/(a/d)+1;
 92     if(ans<=ma) printf("%lld\n",ans);
 93     else puts("ZenMeZheMeDuo");
 94 }
 95 int main()
 96 {
 97 //    freopen("data.in","r",stdin);
 98 //    freopen("data.out","w",stdout);
 99     int T=read();
100     while(T--)
101     {
102         a=read(); b=read(); c=read();
103         if(c<0) a=-a,b=-b,c=-c;
104         if(a<b) a^=b^=a^=b;
105         if(a==1&&b==1)
106         {
107             sol_1();
108             continue;
109         }
110         if(a+b==c)
111         {
112             sol_3();
113             continue;
114         }
115         if(a>0&&b>0&&c>0&&a<=1000&&b<=1000&&c<=1000)
116         {
117             sol_2();
118             continue;
119         }
120         if(c==0)
121         {
122             if((a>0&&b<0)||(a<0&&b>0))
123             {
124                 puts("ZenMeZheMeDuo");
125                 continue;
126             }
127             if((a>0&&b>0)||(a<0&&b<0))
128             {
129                 puts("0");
130                 continue;
131             }
132             if(a==0&&b==0)
133             {
134                 puts("ZenMeZheMeDuo");
135                 continue;
136             }
137         }
138         if(a==0&&b==0&&c)
139         {
140             puts("0");
141             continue;
142         }
143         if(a&&b==0)
144         {
145             if(c%a||c/a<=0)
146             {
147                 puts("0");
148                 continue;
149             }
150             else
151             {
152                 puts("ZenMeZheMeDuo");
153                 continue;
154             }
155         }
156         if(a==0&&b)
157         {
158             if(c%b||c/b<=0)
159             {
160                 puts("0");
161                 continue;
162             }
163             else
164             {
165                 puts("ZenMeZheMeDuo");
166                 continue;
167             }
168         }
169         sol_4();
170     }
171 }
172 inline ll read()
173 {
174     ll x=0,f=1;
175     char tc=getchar();
176     while(tc<'0'||tc>'9')
177     {
178         if(tc=='-') f=-1;
179         tc=getchar();
180     }
181     while(tc>='0'&&tc<='9')
182     {
183         x=x*10+tc-48;
184         tc=getchar();
185     }
186     return f*x;
187 }
View Code

 

 

B. visit

这是一道孤儿题(以至于放错题)

换了题后去码了T1,然后来看T2

说实话首先想到了矩阵快速幂,后来刚想码一想不对啊,这是二维模型,所以矩阵的大小是$(100 \times 100)^2$然后就弃了。

又想到了dp,但是我当时nc了,看着列出的dp[t][i][j]=dp[t-1][i][j-1]+dp[t-1][i][j+1]+dp[t-1][i-1][j]+dp[t-1][i+1][j] 居然认为有后效性?因为我忘了t这一维。。。然后就想起学长曾经讲过的一道类似的但是可以原地不动的题,做法是系数递推,然而我除了知道这个学术名词外没别的了。。。

后来就只能打了个nc bfs 0分。。。

 

正解:组合数学

用skyh的思路。我们只要枚举其中一个方向上的移动,就可以推知其他方向,然后我们就有了$O(n)$枚举+组合数学的方法。

i是上下方向走的步数

$ans= \sum\limits_{i=n}^{T-m} C_T^i \times C_i^{ \frac {i-n} {2}} \times C_{T-i}^{\frac {T-i-m} {2}}$   2|i-n  &&  2|T-i-m

对于$\frac {i-n} {2}$可以这样理解:

i-n是向上多走的步数,由对称性可知再向下回来需要$\frac {i-n} {2}$  那么柿子就没问题了

 

接下来是如何计算。

因为mod不全是质数,那么费马小定理,逆元递推统统失效,组合数不可直接求不来。

我们观察到对于全部数据mod为若干不同质数的乘积,我们可以把mod分解质因数然后分别用质因子 lucas算上面的柿子,最后会得到类似于

$x \equiv a_1(mod m_1) \\ x \equiv a_i (mod m_i) \\ .\\.\\.$

的方程组,其中m互质。这不就是crt嘛!然后合并一波得解。

细节:

质因数分解用试除法

可知质因数上限远不到有$log(\sqrt{mod})$ ,这样就确保了复杂度

所以lucas需要的阶乘直接打表到min(T,p[i])即可$C_{n \% p[i]}^{m \% p[i]}$上下一定<p[i]

 

C. 光

这是一道STL综合模拟题。

暴力可得60pts,当时考试暴力dfs怕爆栈设了29000层上限,然后就50了。。。

听XR说题面给了自开栈,然后就试了一波20w层,也没问题。。。

 

正解:

首先要知道以下几个性质:

  • x+y+dir(两个方向)的奇偶性不变,我们只要知道了坐标,就能推之两个方向
  • 光线一定能回到起点,这个去看wd大神的证明
  • 如果出现了2 4情况,则光路走了两遍

暴力有很多块是空心的,从而局限了复杂度,那么我们是否能直接找到下一个障碍呢?

可知在同一条直线上x+y 或 x-y 为定值,例如x-y=z的情况,那么z就可以代表这条直线。

所以我们可以建两个桶set,用于存储/ \两个方向的所有直线上的障碍物x坐标,对于x-y会有负值加上FIX=10w即可

接下来是模拟: 假设我们在(x,y)方向为dir

那么根据dir分类讨论

由当前x可以在桶里$O(logk)$二分出前趋或后继nx,即下一个障碍物,然后算出ny,然后模拟完事。

posted @ 2019-07-24 06:29  hzoi_yzh  阅读(217)  评论(0编辑  收藏  举报