20161031的考试】模拟,暴力取模+矩阵快速幂,搜索脸的dp

20 篇文章 0 订阅
16 篇文章 0 订阅

首先……我要大喊三声flaze煞笔


T2……当时刚写完不知哪儿抽了手一抖一个shift+del删源码,解锁成就【mdzz】,然后重写的时候,果断脑残取模优化GG

嗯……T3莫名其妙WA了一年,这种瘠薄题拿头来WA啊【跪地】……最后发现……调试的时候数组开小了,然后……タマダ,没删调,GGGGGG

……


T1:煞笔模拟题,没什么好说的

T2:

题面:……求 fib(fib(n)) % (1e9+7) 的值,n是1e100。

思路:显然找规律,于是发现 fib(i)%(1e9+7) 的 i 的循环节是 2e9+16 , 于是内层fib相当于是%(2e9+16) 的,继续暴力找循环节,发现这货的循环节是329616 【把模数写出来就是为了破坏将来如果会复习的flaze的游戏体验喵嘿嘿你回来打我啊23333】嗯,找到循环节之后矩阵快速幂一下,完了

代码:

#include<bits/stdc++.h>
#define MOD 1000000007
using namespace std;	int T;	long long n;
const long long MOD3 = 329616;

char read_s[105];
inline long long read(){
	scanf("%s",read_s);
	char *s=read_s;
	long long f=1,rtn=0;
	if(*s=='-')	f=-1,++s;
	for(;*s;++s){
		rtn=rtn*10+*s-'0';
		if(rtn>=MOD3)	rtn-=MOD3;
	}
	return f*rtn;
}

struct Matrix{
	int x,y;
	int mod;
	int d[2][2];
	Matrix():x(0),y(0){memset(d,0,sizeof d);}
	Matrix(int x):x(x),y(x){memset(d,0,sizeof d);for(int i=0;i<x;++i)	d[i][i]=1;}
	Matrix(int x,int y):x(x),y(y){memset(d,0,sizeof d);}
	
	Matrix operator * (const Matrix ano){
		Matrix RTN(x,ano.y);
		RTN.mod=this->mod;
		for(int i=0;i<x;++i)
			for(int j=0;j<y;++j)
				for(int k=0;k<ano.y;++k)
					RTN.d[i][k]=(RTN.d[i][k]+1ll*d[i][j]*ano.d[j][k]%mod)%mod;
		return RTN;
	}
	Matrix pow(long long c){
		if(!c){
			Matrix RTN=Matrix(2,2);
			RTN.mod=this->mod;
			return RTN;
		}
		--c;
		Matrix RTN(x),TMP=*this;
		RTN.mod=this->mod;
		for(;c;c>>=1,TMP=TMP*TMP)
			if(c&1)
				RTN=RTN*TMP;
		return RTN;
	}
}ori1,ori2,trans1,trans2;

void init(){
	ori1=Matrix(2,1);
	ori1.mod=2000000016;

	ori2=Matrix(2,1);
	ori2.mod=MOD;
	
	trans1=trans2=Matrix(2,2);
	ori1.d[0][0]=ori2.d[0][0]=1;
	ori1.d[1][0]=ori2.d[1][0]=0;
	trans1.d[0][0]=trans1.d[0][1]=1;
	trans2.d[0][0]=trans2.d[0][1]=1;
	trans1.d[1][0]=trans2.d[1][0]=1;
	
	trans1.mod=2000000016;
	trans2.mod=MOD;
}

int fib(long long i){
	Matrix TMP=trans1.pow(i)*ori1;
	i=(long long)TMP.d[0][0];
	TMP=trans2.pow(i)*ori2;
	int k=TMP.d[0][0];
	return k;
}


int main(){
	freopen("na.in","r",stdin);
	freopen("na.out","w",stdout);
	init();
	
	scanf("%d",&T);
	while(T--){
		n=read();
		printf("%d\n",fib(n));
	}
	
	return 0;
}




T3:…………我cnmb打的是友军x

    题面:

你现在希望组建一支足球队,一支足球队一般来说由11人组成。 这11人有四
种不同的职业:守门员、后卫、中锋、前锋组成。你在组队的时候必须满足以下
规则:
1、 足球队恰好由11人组成。
211人中恰好有一名守门员, 3-5 名后卫, 2-5 名中锋, 1-3 名前锋。
3、 你需要从这11人中选出一名队长。
4、 你这个足球队的价值是11人的价值之和再加上队长的价值,也就是说
队长的价值会被计算两次。
5、 你这个足球队的花费是11人的花费之和,你的花费之和不能超过给定
的上限。
现在告诉你球员的总数,每个球员的职业、价值、花费,以及花费的上限,
你希望在满足要求的情况下,达到以下目标:
1、 最大化队伍的价值。
2、 在最大化队伍的价值的情况下,最小化队伍的花费。
3、 在满足以上两个要求的情况下,有多少种选择球员的方案。如果有两
种方案它们的区别仅仅是队长不一样,那么这两种方案应该被认为是一样的


思路:排序之后sb魔改背包,f[a][b][c][d][cc]表示四种分别有几个,花费为cc的最大value,方案数,队长的值(显然应该是当前的最大值最优)

代码:

#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXM 1005
#define MOD 1000000000
#define INF 0x3f3f3f3f
using namespace std;	int n,lim;

struct t2{
	int value,cost,type;
	t2():value(0),cost(0),type(0){}
	t2(int value,int cost,int type):value(value),cost(cost),type(type){}
	bool operator < (const t2 &ano)const{
		return value==ano.value? cost>ano.cost: value<ano.value;
	}
}p[MAXM];

struct t1{
	int value,cnt,mx;
	t1():value(0),cnt(0),mx(0){}
	t1(int value,int cnt,int mx):value(value),cnt(cnt),mx(mx){}
}f[2][6][6][4][MAXM];

int llimit[5]={0,1,3,2,1};
int rlimit[5]={0,1,5,5,3};

char read_s[20];
int read_v,read_c;
inline void init(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%s%d%d",read_s,&read_v,&read_c);
		if(read_s[0]=='G')	p[i]=t2(read_v,read_c,1);
		if(read_s[0]=='D')	p[i]=t2(read_v,read_c,2);
		if(read_s[0]=='M')	p[i]=t2(read_v,read_c,3);
		if(read_s[0]=='F')	p[i]=t2(read_v,read_c,4);
	}
	scanf("%d",&lim);
	sort(p+1,p+n+1);
}

inline void make_F(){
	f[0][0][0][0][0]=t1(0,1,-1);
	for(int i=1;i<=n;++i)
		for(int a=rlimit[1]-(p[i].type==1);~a;--a)
			for(int b=rlimit[2]-(p[i].type==2);~b;--b)
				for(int c=rlimit[3]-(p[i].type==3);~c;--c)
					for(int d=rlimit[4]-(p[i].type==4);~d;--d){
						if(a+b+c+d>=11)	continue;
						for(int cc=lim-p[i].cost;~cc;--cc){
							t1 tmp=f[a][b][c][d][cc],
							   &aim=f[a+(p[i].type==1)][b+(p[i].type==2)]
								     [c+(p[i].type==3)][d+(p[i].type==4)]
								     [cc+p[i].cost];
							if(!tmp.cnt)	continue;
							int kk = tmp.value + p[i].value;
							if(kk > aim.value){
								aim.value = kk;
								aim.cnt = tmp.cnt;
								aim.mx = p[i].value;
							}
							else{
								if(kk == aim.value){
									if(p[i].value > aim.mx)
										aim.cnt = tmp.cnt , aim.mx = p[i].value;
									else{
										if(p[i].value == aim.mx)
											aim.cnt += tmp.cnt;
									}
								}
							}
							if(aim.cnt > MOD) aim.cnt=MOD;
						}
					}
}

inline void get_ans(){
	int ans_value=0,ans_cost=INF,ans_cnt=0;
	
	for(int a=llimit[1];a<=rlimit[1];++a)
		for(int b=llimit[2];b<=rlimit[2];++b)
			for(int c=llimit[3];c<=rlimit[3];++c)
				for(int d=llimit[4];d<=rlimit[4];++d){
					if((a+b+c+d)^11)	continue;
					for(int cc=0;cc<=lim;++cc){
						t1 now=f[a][b][c][d][cc];
						if(!now.cnt)	continue;
						if(now.value + now.mx > ans_value){
							ans_value = now.value + now.mx;
							ans_cost = cc;
							ans_cnt = now.cnt;
						}
						else	if(now.value + now.mx == ans_value){
									if(cc == ans_cost)	ans_cnt += now.cnt;
									else	if(cc < ans_cost)
												ans_cost = cc , ans_cnt = now.cnt;
								}
						if( ans_cnt>MOD ) ans_cnt=MOD; 
					}
				}
	printf("%d %d %d",ans_value,ans_cost,ans_cnt);
}

int main(){
	init();
	make_F();
	get_ans();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值