好久没有打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; } } }