好久没有打BestCoder了(其实一直都在打,不过涨涨跌跌,就没高兴写题解),昨天做了一波,竟然都是我最喜欢的数学题。当然做得不错,成功上了1900,虽然有点运气的成分。
第一题 hdu-5665
分析:首先一点,写得快的人第一次交都PE了(我也是),出题人说数据没问题,最后也不了了之了(吐槽免不了)。打比赛的时候好多人对自然数的定义有异议,不知道0算不算自然数,我记得小学就学了0算自然数(0怎么不自然了=。=)。这道题算简单的把,毕竟第一题。就是判断一下,这些数集里面有没有0和1,0不用说,没有任何数相加可以得到0的,除了0,所以0必须要有。然后对于1,当然也没有数相加可以得到1,除了1自身,所以1必须要有。但是既然有了1的话其他所有自然数都可以得到了,那么只需要判断一下0和1是否存在于数集即可。
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define clr(x,y) memset(x,y,sizeof(x))
#define rep(i,n) for(int i=0;i<(n);i++)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define maxn 1000000+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define IT iterator
#define push_back PB
typedef long long ll;
const double eps = 1e-10;
const double pi = acos(-1);
const ll mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int main()
{
//freopen("d:\\acm\\in.in","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
int n,a;
int k=0,h=0;
scanf("%d",&n);
while(n--)
{
scanf("%d",&a);
if(a==0)k=1;
if(a==1)h=1;
}
if(k&&h)puts("YES");
else puts("NO");
}
return 0;
}
分析:第二题是我最想吐槽的一道题,出题人语文水平真心有问题,我看了半天一点没看懂(=。=)。最后还是对亏了Acfun的大神,无意中透露一点信息,我才知道原来题目是唬人的。虽然连了那么多线段,但是因为P是质数,所以不可能有任何整点在后来连起来的线段上,结论就是完全不用看这些,直接1+2+3+......+(p-2),当然是等差数列求和公式,唯一的坑点就是两个long long相乘爆掉把,好多小朋友非常可惜的被hack了(我也hack了两个)。我只能说这回学到了把,有个神奇的东西叫快速幂加法,虽然并没有变的很快,但是两个longlong相乘取模不会爆longlong。
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define clr(x,y) memset(x,y,sizeof(x))
#define rep(i,n) for(int i=0;i<(n);i++)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define maxn 1000000+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define IT iterator
#define push_back PB
typedef long long ll;
const double eps = 1e-10;
const double pi = acos(-1);
const ll mod = 1e9+7;
const int inf = 0x3f3f3f3f;
ll p;
ll mul(ll a,ll b)
{
ll ans=0;
while(b)
{
if(b&1)ans=(ans+a)%p;
a=(a+a)%p;
b>>=1;
}
return ans;
}
int main()
{
//freopen("d:\\acm\\in.in","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
ll q;
scanf("%I64d %I64d",&q,&p);
if(q==2)
{
puts("0");
continue;
}
ll ans=mul((q-1)/2,(q-2));
printf("%I64d\n",ans);
}
return 0;
}
分析:最近刚刷完矩阵快速幂专题,要是这道题都不会的话,也是真的醉了。稍微写上几个f(n),很显然的看到了递推式主要体现在了指数上,那么不用管a^b,只要先求指数,然后再来一遍整数快速幂即可。考虑,不妨设一个新的数列G(n),G(1)=0,G(2)=1,G(n)=c*G(n-1)+G(n-2)+1。看过我前一个专题的人,应该很简单的就可以构造出矩阵。
注意:这里面有个坑点,对于矩阵内部取模的话,是不可以用p的(p是对底数取模,而不是指数,这里求的是指数),根据费马小定理要用p-1。但是有一个问题,对于a%p==0的情况,那么底数显然是0,只要构造一个指数正好能被p-1整除的情况,就会意外的出现0的0次方的情况(其实数学上是不存在0的0次方的),最后结果是1,但是正确是0。对于这种情况只要特判一下就行了,对于求逆元都有这种情况啊。我的代码是非常猥琐的躲过的这个问题,我的矩阵结果最后一次是直接加的,没有取模(我不记得是忘了还是什么=。=),所以基本没有能够hack掉我的代码的数,虽然看上去不是标准答案啦。(这里贴我的代码了)
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define clr(x,y) memset(x,y,sizeof(x))
#define rep(i,n) for(int i=0;i<(n);i++)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define maxn 0+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define IT iterator
#define push_back PB
typedef long long ll;
const double eps = 1e-10;
const double pi = acos(-1);
const ll mod = 1e9+7;
const int inf = 0x3f3f3f3f;
ll p;
ll q;
ll low(ll a,ll n)
{
ll ans=1;
while(n)
{
if(n&1)ans=ans*a%p;
a=a*a%p;
n>>=1;
}
return ans;
}
struct matrix
{
int n;
ll maze[maxn][maxn];
void init(int n)
{
this->n=n;
clr(maze,0);
}
matrix operator * (const matrix& rhs)
{
matrix ans;
ans.init(n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%q;
return ans;
}
};
matrix qlow(matrix a,ll n)
{
matrix ans;
ans.init(a.n);
for(int i=0;i<a.n;i++)ans.maze[i][i]=1;
while(n)
{
if(n&1)ans=ans*a;
a=a*a;
n>>=1;
}
return ans;
}
int main()
{
//freopen("d:\\acm\\in.in","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
ll n,a,b,c;
scanf("%I64d %I64d %I64d %I64d %I64d",&n,&a,&b,&c,&p);
ll ans=low(a,b);
if(n<=2)
{
if(n==1)printf("%I64d\n",1%p);
else printf("%I64d\n",ans);
continue;
}
q=p-1;
matrix ant;
ant.init(3);
ant.maze[0][0]=ant.maze[0][2]=ant.maze[1][2]=ant.maze[2][1]=1;
ant.maze[2][2]=c;
ant=qlow(ant,n-2);
ans=low(ans,ant.maze[0][2]+ant.maze[2][2]);
printf("%I64d\n",ans);
}
return 0;
}
分析:很久很久以前学过同余方程组,不过很遗憾忘光了。=。=
贴一下学长的代码
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define PB push_back
#define SIZE(x) (int)x.size()
#define clr(x,y) memset(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ALL(t) (t).begin(),(t).end()
#define FOR(i,n,m) for (int i = n; i <= m; i ++)
#define ROF(i,n,m) for (int i = n; i >= m; i --)
#define RI(x) scanf ("%d", &(x))
#define RII(x,y) RI(x),RI(y)
#define RIII(x,y,z) RI(x),RI(y),RI(z)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
const ll mod = 1e9+7;
const ll LINF = 1e18;
const int INF = 1e9;
const double EPS = 1e-8;
/**************************************END************************************/
void ext_gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b)
{
x=1;
y=0;
d=a;
return ;
}
else
{
ext_gcd(b,a%b,d,y,x);
y-=a/b*x;
}
}
vector<int> a, b;
ll solve()///x=b[i](mod a[i])
{
ll ta=a[0],tb=b[0];
bool flag=true;
for(int i=1; i<SIZE (a); i++)
{
ll xa=ta,xb=a[i],c=b[i]-tb,d,x,y;
ext_gcd(xa,xb,d,x,y);
if(c%d)
{
flag=false;
break;
}
ll tmp=xb/d;
x=(x*(c/d)%tmp+tmp)%tmp;
tb=ta*x+tb;
ta=ta/d*a[i];
}
if(!flag) return -1;
return tb;
}
int main (){
int T;
cin >> T;
while (T --){
a.clear ();
b.clear ();
int n;
cin >> n;
vector<bool> vis(n);
int now = -1;
vector<int> vec(n+1);
FOR (i, 1, n){
int t;
cin >> t;
vec[t] = i;
}
ROF (i, n, 1){
int cnt = 0;
int t = vec[n-i+1];
t --;
while (now != t){
now ++;
if (now >= n){
now = 0;
}
if (!vis[now]){
cnt ++;
}
}
vis[t] = true;
a.PB (i);
b.PB (cnt-1);
}
// FOR (i, 0, n-1){
// cout << a[i] << " ";
// }
// cout << endl;
// FOR (i, 0, n-1){
// cout << b[i] << " ";
// }
// cout << endl;
ll ans = solve () + 1;
if (ans == 0){
puts ("Creation August is a SB!");
}else{
cout << ans << endl;
}
}
}