标签:



这一道题有两种做法:
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