2016 北京 ICPC (部分)

I - A Boring Problem

 题目大意 

数列求和,其中每一项都是一个子段和的k次幂,例如:

给定原字符串为  “12345”

输出结果:1^k  (1+2)^k+2^k  (1+2+3)^k+(2+3)^k+3^k…… (1+2+3+4+5)^k+(2+3+4+5)^k+…+5^k                                       

正常思路下,每个输出结果也需分别进行求和,即使用了快速幂,最后复杂度为 n^2log(n) 依然会超时,所以需优化。

将每个输出结果中的每一个加项用二项式定理展开,提取二项式系数,此时由n项变为了k项,复杂度可以降低为n*k,但需进行

大量预处理工作。

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

#define M 105
#define N 50005
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define mod 1000000007
long long coef[N][M],sum[N][M],c[M],ss[N][M];
char s[N];
int n,k,t;

int main() {
	scanf("%d",&t);
	while(t--) {
		memset(sum,0,sizeof(sum));
		memset(coef,0,sizeof(coef));
		memset(ss,0,sizeof(ss));
		scanf("%d%d",&n,&k);
		scanf("%s",s+1);

		rep(i,1,n) ss[i][1]=ss[i-1][1]+s[i]-'0',ss[i][0]=1;
		rep(i,2,k) rep(j,1,n) ss[j][i]=(ss[j][i-1]*ss[j][1])%mod;

		c[0]=1;
		rep(i,1,k) c[i]=c[i-1]*(k-i+1)/i%mod;

		sum[0][0]=1;
		rep(i,0,k) rep(j,1,n) sum[j][i]=(long long)(sum[j-1][i]+ss[j][i])%mod;
		rep(i,1,n) rep(j,0,k) {
			coef[i][j]=ss[i][k-j]*c[j]%mod;
			coef[i][j]*=(j%2?-1:1);
		}
		rep(i,0,n-1) {
			long long ans=0;
			rep(j,0,k) {
				ans+=coef[i+1][j]*(sum[i][j])%mod;
				ans%=mod;
			}
			printf("%ld%c",ans,i==n-1?'\n':' ');
		}
	}
	return 0;
}

只不过最后还是tle……其中原因有待进一步分析

 

 

E. What a Ridiculous Election

bfs

题目大意:对于一个长度为5的数字序列有三种操作

1.交换相邻的两个数字

2.将某个数字加一(对10取余)

3.将某个数字乘二(对10取余)

其中操作2,3分别能进行3次和2次,操作1可以进行无限多次,目标:在每一个query中,读入目标序列,求出并输出将 12345 

变换至目标序列所需最小操作数,如果无法达到目标序列 ,输出 -1 。

思路:bfs预处理

从 12345 出发找到所有能达到的情况并记录最小操作数;

结果记录在 ans[100000][4][3]中,ans[num][i][j]代表

设计记录一个状态的结构体,括号中为初始状态

{

int num[6];   //到达序列 (1,2,3,4,5)

int op2,op3; //剩余操作2,3个数 (3,2)

int step;       //已使用操作总数 (0)

}

bfs函数中,对于队列顶端状态,分别进行操作1,2,3的尝试变为新状态,如果发现对应状态在ans中存储的结果大于当前状态下的step,则进行更新,并将该状态压入队列,最后当队列为空的时候,则已走遍所有可达到状态。

 


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>

using namespace std;

struct node {
	int num[7];
	int op2;
	int op3;
	int step;
};
int ans[100005][4][4];
int q_num(node t) {
	int sum=0;
	for(int i=1; i<=5; i++){
		sum+=t.num[i];
		sum*=10;
	}
	return sum/10;
}

void bfs(node t) {
	queue<node>q;
	memset(ans,0x3f,sizeof(ans));
	t.op2=3;
	t.op3=2;
	t.step=0;
	q.push(t);
	int n=q_num(t);
	ans[n][t.op2][t.op3]=0;
	while(!q.empty()) {
		node p=q.front();
		q.pop();

		for(int i=2; i<=5; i++) {
			node tp=p;
			swap(tp.num[i-1],tp.num[i]);
			int num=q_num(tp);
			tp.step++;
			if(tp.step>=ans[num][tp.op2][tp.op3])
				continue;
			q.push(tp);
			ans[num][tp.op2][tp.op3]=tp.step;
		}
		if(p.op2>0) {
			for(int i=1; i<=5; i++) {
				node tp=p;
				tp.op2--;
				tp.num[i]=(tp.num[i]+1)%10;
				int num=q_num(tp);
				tp.step++;
				if(ans[num][tp.op2][tp.op3]<=tp.step)
					continue;
				q.push(tp);
				ans[num][tp.op2][tp.op3]=tp.step;
			}
		}
		if(p.op3>0) {
			for(int i=1; i<=5; i++) {
				node tp=p;
				tp.op3--;
				tp.num[i]=(tp.num[i]*2)%10;
				int num=q_num(tp);
				tp.step++;
				if(ans[num][tp.op2][tp.op3]<=tp.step)
					continue;
				q.push(tp);
				ans[num][tp.op2][tp.op3]=tp.step;
			}
		}
	}
}

int main() {
	char test[9];
	node init;
	for(int i=1; i<=5; i++)
		init.num[i]=i;
	bfs(init);

	while(~scanf("%s",test+1)) {
		int query=0;
		for(int i=1; i<=5; i++) {
			query+=(test[i]-'0');
			query*=10;
		}
		query/=10;
		int res=0x3f3f3f3f;
		for(int i=0; i<=3; i++)
			for(int j=0; j<=2; j++)
				res=min(res,ans[query][i][j]);
		if(res==0x3f3f3f3f)
			cout<<-1<<endl;
		else
			cout<<res<<endl;
	}
	return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Absoler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值