1. 1001-HDU 5793 A Boring Question
题意:给定n,m,求的值。其中。
题解:
二项式定理:
特别的,
即,
其中
。
所以:
用快速幂来求解m^(n+1)由于要取模,但是有除法所以用费马小定理可得:a / c mod p== a * c^(p-2) mod p。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MOD=1000000007;
typedef long long LL;
LL Pow(LL a,LL n)
{
LL ans=1;
while(n){
if(n&1)ans=ans*a%MOD;
n>>=1;
a=a*a%MOD;
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
LL n,m;
scanf(" %I64d %I64d",&n,&m);
printf("%I64d\n",(Pow(m,n+1)-1)*Pow(m-1,MOD-2)%MOD);
}
return 0;
}
2. 1002- HDU 5794 A Simple Chess
题意:一个n*m的棋盘,一个棋子想从(1,1)走到(n,n),棋子每步可从(x1,y1)到达(x2,y2),
当且仅当
另外,棋盘上有r处障碍,棋子无法到达障碍处,问棋子从(1,1)到达(n,m)有多少种走法?
题解:
根据题意,棋子只能走(x+1,y+2)①或者(x+2,y+1)②这两个方向 ,所以只有满足一定条件的位置才有可能到达。我们假设①方向走了a步,②方向走了b步,那么我们可以得到满足条件的位置一定是x=a+2b,y=2a+b,所以可以得到只有(x+y)是3的整数倍的位置才有可能到达。并且(1/2<=y/x<=2)。
我们先不考虑障碍物,则到达每个点的方案数构成一个杨辉三角,即每个点的方案数等于它两肩上的数之和。我们可以用坐标计算出这个点在杨辉三角中的 位置。杨辉三角第x行第y列(x,y下标均从0开始)的数为组合数C(x,y),大数组合数用Lucas定理。
然后考虑障碍物,到达终点的方案数等于(不考虑障碍物的方数)-(起点到障碍物的方案数)*(障碍物到终点的方案数),而(起点到障碍物的方案数)的计算也要减去其他障碍物对它的影响。
代码 :
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX=100+5;
const int MOD=110119;
typedef long long LL;
struct node
{
LL x,y,val;
node(LL _x=0,LL _y=0,LL _val=0):x(_x),y(_y),val(_val) {};
bool operator <(const node &a) const
{
return this->x<a.x||(this->x==a.x&&this->y<a.y);
}
} ob[MAX];
LL f[200000];
void init(int p)
{
f[0] = 1;
for(int i = 1; i <= p; ++i)
f[i] = f[i-1] * i % p;
}
LL pow_mod(LL a, LL x, int p)
{
LL ret = 1;
a %= p;
while(x)
{
if(x & 1)
{
ret = ret * a % p;
--x;
}
else
{
a = a * a % p;
x >>= 1;
}
}
return ret;
}
LL Lucas(LL n, LL k, int p)
{
LL ret = 1;
while(n && k)
{
LL nn = n % p, kk = k % p;
if(nn < kk) return 0;
ret = ret * f[nn] * pow_mod(f[kk] * f[nn - kk] % p, p - 2, p) % p;
n /= p;
k /= p;
}
return ret;
}
LL waycnt(LL x1,LL y1,LL x2,LL y2,int p)
{
LL x=x2-x1;
LL y=y2-y1;
if((x1+y1)%3!=2) return 0;
if((x2+y2)%3!=2) return 0;
if((x+y)%3!=0) return 0;
LL row=(x+y)/3;
LL col=x-row;
if(col<0||col>row) return 0;
return Lucas(row,col,p);
}
int main()
{
init(MOD);
int tcase=1;
LL n,m,r;
while(cin>>n>>m>>r)
{
for(int i=0; i<r; i++)
{
cin>>ob[i].x>>ob[i].y;
}
sort(ob,ob+r);
for(int i=0; i<r; i++)
{
ob[i].val=waycnt(1,1,ob[i].x,ob[i].y,MOD);
for(int j=0; j<r; j++)
{
if(ob[j].x<ob[i].x&&ob[j].y<ob[i].y)
ob[i].val=((ob[i].val-(ob[j].val*waycnt(ob[j].x,ob[j].y,ob[i].x,ob[i].y,MOD)%MOD))%MOD+MOD)%MOD;
}
}
LL ans=waycnt(1,1,n,m,MOD);
for(int i=0; i<r; i++)
{
if(ob[i].x==n&&ob[i].y==m)
{
ans=0;
break;
}
if(ob[i].x<n&&ob[i].y<m)
ans=((ans-(ob[i].val*waycnt(ob[i].x,ob[i].y,n,m,MOD)%MOD))%MOD+MOD)%MOD;
}
printf("Case #%d: %I64d\n",tcase++,ans);
}
return 0;
}
3. 1010-HDU 5802 Windows 10
题意:windows 10 调音量。
按up键可以往上调高一个DB,按down键可以向下调x个DB,如果上一次是按的up键或者上一次是停止,x=1,如果上次按的是down键,且向下降了xDB,则x=2*x。要求从p调到q,最少需要多少次按键?
题解:
显然,如果p<=q,则只能一次一次向上调,答案为q-p;
如果p>q,那么最少的步数为:
一直指数下降,下降到大于q的最小的那个数,然后停一次,再继续指数下;
或者下降到小于q的最大的那个数,然后在向上升回去。
比较两种情况所需的步数,取最小值。
需要注意的是:
1. 音量不能小于0;
2. 由于up和停止都可以使得x变为1,所以可以在用上升来抵消停顿,即在需要停一次的时候向上升1DB,这样可以使得下降到比q小时少上升几次。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long LL;
LL dfs(LL s,LL t,LL step,LL rest)
{
if(s==t) return step;
LL x=0;
while(s-(1<<x)+1>t) x++;
if(s-(1<<x)+1==t) return step+x;
LL up=t-max(s-(1<<x)+1,0ll);
return min(step+x+max(0ll,up-rest),dfs(s-(1<<(x-1))+1,t,step+x,rest+1));
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int p,q;
scanf("%d%d",&p,&q);
if(p<=q) printf("%d\n",q-p);
else printf("%I64d\n",dfs(p,q,0,0));
}
return 0;
}