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