标签:
这一道题有两种做法:
1:构建矩阵,根据斐波拉契数列数列类比,得到矩阵过后根据fi直接解出t(因为fi是小于19960515的所以过程中不会去"%",所以可以直接除以系数,不
用逆元),再用矩阵算出fj
|fn+1 | |1 1|n * |f1|
|fn | |0 1| * |f0|
2:找规律推性质:
f0 = 1
f1 = 1t
f2 = 1t + 1
f3 = 2t + 1
f4 = 3t + 2
f5 = 5t + 3
那么归纳得fn = Fn-1*t + Fn-2 Fn是斐波拉契数列第n项
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int mod = 19960515; struct Matrix{ int map[3][3]; void init(bool flag){ memset(map,0,sizeof(map)); if(flag)for(int i = 0;i < 3;++i)map[i][i] = 1; } }ori,pou; Matrix mul(Matrix x,Matrix y){ Matrix ret;ret.init(0); for(int i = 0;i < 3;++i){ for(int j = 0;j < 3;++j){ for(int k = 0;k < 3;++k){ ret.map[i][j] = (ret.map[i][j]+(long long)x.map[i][k]*y.map[k][j])%mod; } } } return ret; } Matrix Pow(Matrix x,int cnt){ Matrix ret;ret.init(1); while(cnt){ if(cnt & 1)ret = mul(ret,x); x = mul(x,x); cnt>>=1; } return ret; } int main(){ freopen("gibonacci.in","r",stdin); freopen("gibonacci.out","w",stdout); int T,xi,i,j,t; scanf("%d",&T); ori.map[0][0] = 1,ori.map[0][1] = 1; ori.map[1][0] = 1,ori.map[1][1] = 0; while(T--){ scanf("%d%d%d",&i,&xi,&j); Matrix ret;ret.init(0); ret = Pow(ori,i); if((xi-ret.map[1][1]) % ret.map[1][0] != 0){ printf("-1\n"); continue; } t = (xi-ret.map[1][1]) / ret.map[1][0]; Matrix k;k.init(0); k.map[0][0] = t;k.map[1][0] = 1; ret = Pow(ori,j); ret = mul(ret,k); printf("%d\n",ret.map[1][0]); } return 0; }
就是一个爆搜,但这种有一次性物品的需要记录状态和回溯。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; const int inf = 1<<30; int ans = inf; int hash[1010][30][100],T,n,m,h,S; const int dx[] = {-1,1,0,0}; const int dy[] = {0,0,-1,1}; #define unlegal(x,y) x<0 || x>=n || y<0 || y>=m char map[20][20]; void dfs(int pos,int hp,int kill){ if(hp < 0)return; if(kill > ans)return; if(hash[pos][hp][kill] == T)return; hash[pos][hp][kill] = T; int x = pos/m,y = pos%m; for(int i = 0;i < 4;++i){ int _x = x+dx[i], _y = y+dy[i]; if(unlegal(_x,_y))continue; if(map[_x][_y] == ‘#‘)continue; if(map[_x][_y] == ‘.‘ && hash[_x*m+_y][hp][kill]!=T)dfs(_x*m+_y,hp,kill); if(map[_x][_y] == ‘M‘){ map[_x][_y] = ‘.‘; dfs(_x*m+_y,hp-1,kill+1); map[_x][_y] = ‘M‘; } if(map[_x][_y] == ‘C‘ && hash[_x*m+_y][hp+5][kill]!=T){ map[_x][_y] = ‘.‘; dfs(_x*m+_y,hp+5,kill); map[_x][_y] = ‘C‘; } if(map[_x][_y] == ‘E‘){ ans = min(ans,kill);return; } } } int main(){ freopen("tower.in","r",stdin); freopen("tower.out","w",stdout); while(scanf("%d%d%d",&h,&n,&m)!=EOF){ ++T; ans = inf; for(int i = 0;i < n;++i){ scanf("%s",map[i]); for(int j = 0;j < m;++j){ if(map[i][j] == ‘S‘)S = i*m+j,map[i][j] = ‘.‘; } } dfs(S,h,0); if(ans == inf)puts("Poor Warrior"); else printf("%d\n",ans); } return 0; }
这个题首先分析题目,意思是要求裁判在两点之间并且水平也在两人之间,那么对于每一个人都可以作为一个裁判,那么假设在这个人在i这个点,i之前有x个人水平比他低,那么有i-x-1个人的水平比他高,后面同理,i之后有y个人水平比他低,那么就有n-y-i个人比他高,那么答案就是(n-y-i)*(x)+(i-x-1)*y,怎么维护一段区间比R数小的数的个数呢?很容易想到树状数组。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 200010; #define clr(a,b) memset(a,b,sizeof(a)) #define lowbit(i) i&-i long long T,n,a[N],x[N],y[N]; struct bit{ int c[N]; void init(){clr(c,0);} void update(int x){ for(int i = x;i <= N;i += lowbit(i)){ c[i] += 1; } } int query(int x){ int sum = 0; for(int i = x;i >= 1;i -= lowbit(i)){ sum += c[i]; } return sum; } }f,b; int main(){ freopen("inhouse.in","r",stdin); freopen("inhouse.out","w",stdout); scanf("%I64d",&T); while(T--){ f.init(),b.init(); clr(a,0),clr(x,0),clr(y,0); scanf("%d",&n); for(int i = 1;i <= n;++i)scanf("%I64d",&a[i]); for(int i = 1;i <= n;++i){ x[i] = f.query(a[i]); f.update(a[i]); } for(int i = n;i >= 1;--i){ y[i] = b.query(a[i]); b.update(a[i]); } long long ans = 0; for(int i = 1;i <= n;++i){ ans = ans+(i-x[i]-1)*y[i]+(n-i-y[i])*x[i]; } cout<<ans<<endl; } return 0; }
标签:
原文地址:http://www.cnblogs.com/xgtao984/p/5724111.html