2018_10_5 模拟赛

111 篇文章 0 订阅
99 篇文章 1 订阅

前言

和上一次的区别就是,这周比赛难度稍微地降低
但是,还是太菜了被dalao吊打的恐惧


JZOJ 5791 阶乘

题目

给定 p = Π i = 1 n a [ i ] p=\Pi_{i=1}^n a[i] p=Πi=1na[i],若 p × q = m ! , q ∈ N ∗ p\times q=m!,q\in N* p×q=m!qN
求最小的 m m m


分析

然而这道题不算很难,首先把 p p p分解质因数,(当然不可能直接给 p p p),所以要把 a a a数组分解,那么之后枚举 p p p的质约数,并且判断若要求出 m m m,对于 p p p的质约数或它的倍数,最多得匹配到几才能满足 p p p的该质约数的指数,讲到这里,就讲完了


代码

#include <cstdio>
#define max(a,b) ((a)>(b))?(a):(b)
#define rr register
using namespace std;
int sum[100001];
inline signed in(){
	rr int ans=0; rr char c=getchar();
	while (c<48||c>57) c=getchar();
	while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
	return ans;
}
signed main(){
	while (1){
		rr int n=in();
		while (n--){
			rr int x=in();
			for (rr int j=2;j*j<=x;++j)//分解质因数
			    while (x%j==0) x/=j,sum[j]++;
			if (x>1) sum[x]++;
		}
		break;
	}
	rr int ans=0;
	for (rr int i=2;i<=100000;++i)
	if (sum[i]>0){
		rr int now=i;
		while (sum[i]>0){
			rr int tmp=now; now+=i;
			while (tmp%i==0) sum[i]--,tmp/=i;//最多需要匹配到几才能满足
		}
		ans=max(ans,now-i);//加多了要减回去
	}
	return !printf("%d",ans);
}

JZOJ 5793 小S练跑步

最少拐弯问题加上限制无法走某个方向,广搜就可以过,
放出dalao的题解
没办法,我的代码还是得放上去(感性理解,在此不多赘述)

#include <cstdio>
#include <cstring>
#include <queue>
#define min(a,b) ((a)<(b))?(a):(b)
#define rr register
using namespace std;
struct node{int x,y; char dir;}; queue<node>q;
int dis[503][503][4],n,m; char could[503][503];
int main(){
	freopen("run.in","r",stdin);
	freopen("run.out","w",stdout);
	scanf("%d%d",&n,&m);
	memset(dis,127/3,sizeof(dis));
	dis[1][1][0]=dis[1][1][1]=0;
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=m;++j){
		could[i][j]=getchar();
		while (could[i][j]!='U'&&could[i][j]!='L'&&could[i][j]!='D'&&could[i][j]!='S'&&could[i][j]!='R') could[i][j]=getchar();
	}
	if (could[1][1]=='S') return !printf("No Solution"); 
	if (could[n][m]=='S') could[n][m]='R'; bool flag=0;
	if (could[1][1]!='D') q.push((node){1,1,'D'});
	if (could[1][1]!='R') q.push((node){1,1,'R'});
	while (q.size()){
		rr node t=q.front(); q.pop();
		rr int xx=0,yy=0,ddir;
		if (t.dir=='D'&&t.x<n&&could[t.x+1][t.y]!='S') xx=t.x+1,yy=t.y,ddir=0;
		if (t.dir=='R'&&t.y<m&&could[t.x][t.y+1]!='S') xx=t.x,yy=t.y+1,ddir=1;
		if (t.dir=='U'&&t.x>1&&could[t.x-1][t.y]!='S') xx=t.x-1,yy=t.y,ddir=2;
		if (t.dir=='L'&&t.y>1&&could[t.x][t.y-1]!='S') xx=t.x,yy=t.y-1,ddir=3;
		if (!xx||!yy) continue;
		if (could[xx][yy]!='D'&&dis[xx][yy][0]>dis[t.x][t.y][ddir]+(t.dir!='D'&&(xx!=n||yy!=m)))
			dis[xx][yy][0]=dis[t.x][t.y][ddir]+(t.dir!='D'&&(xx!=n||yy!=m)),q.push((node){xx,yy,'D'});
		if (could[xx][yy]!='R'&&dis[xx][yy][1]>dis[t.x][t.y][ddir]+(t.dir!='R'&&(xx!=n||yy!=m)))
			dis[xx][yy][1]=dis[t.x][t.y][ddir]+(t.dir!='R'&&(xx!=n||yy!=m)),q.push((node){xx,yy,'R'});
		if (could[xx][yy]!='U'&&dis[xx][yy][2]>dis[t.x][t.y][ddir]+(t.dir!='U'&&(xx!=n||yy!=m)))
			dis[xx][yy][2]=dis[t.x][t.y][ddir]+(t.dir!='U'&&(xx!=n||yy!=m)),q.push((node){xx,yy,'U'});
		if (could[xx][yy]!='L'&&dis[xx][yy][3]>dis[t.x][t.y][ddir]+(t.dir!='L'&&(xx!=n||yy!=m)))
			dis[xx][yy][3]=dis[t.x][t.y][ddir]+(t.dir!='L'&&(xx!=n||yy!=m)),q.push((node){xx,yy,'L'});
	} 
	rr int ans=min(min(dis[n][m][0],dis[n][m][1]),min(dis[n][m][2],dis[n][m][3]));
	if (ans<707406378) return !printf("%d",ans); else return !printf("No Solution");
}

JZOJ 5787 轨道

题目

v = a 1 × a 2 × ⋯ × a n k v=\frac{a_1\times a_2\times\cdots\times a_n}{k} v=ka1×a2××an
已知 n n n k k k,求这 n n n个正整数在都不大于 m m m的情况下有多少种选择方式,使得 g c d ( v , k ) = 1 gcd(v,k)=1 gcd(v,k)=1


分析

需要数论牵扯,然而这是道动态规划的题目,设 d p [ i ] [ j ] dp[i][j] dp[i][j]为前 i i i个数,乘积与 k k k的最大公约数为 k k k的第 j j j个约数的方案数(且乘积除以公约数与 k k k互质)
容易得到 d p [ i ] [ j ] = d p [ i − 1 ] [ 约 数 ] ∗ d p [ 1 ] [ j / 约 数 ] dp[i][j]=dp[i-1][约数]*dp[1][j/约数] dp[i][j]=dp[i1][]dp[1][j/]
但是如何初始化是个问题,那么就是 m / a [ i ] x = 1 g c d ( x , k ) = 1 的 个 数 。 \frac{m/a[i]}{x=1}gcd(x,k)=1的个数。 x=1m/a[i]gcd(x,k)=1,需要用容斥原理跑深搜,然而我不会莫比乌斯反演怎么做,于是


代码(80分TLE,请自行O2)

#include <cstdio>
#include <algorithm>
#include <vector>
#define answer(t) (dp[kdys2[j][t]][t1^1]*pre[rk[kdys[j]/kdys[kdys2[j][t]]]])//使代码简洁了许多
#define rr register//register的威力
using namespace std;
vector<int>kdys; vector<short>kdys2[3001],prime;//第一个小优化就是变成了short,虽然时间貌似多了点,但是内存比只用int少了一半
int m,k; short n,rk[10000001],dp[3001][2],t1=1,pre[3001];//没错,dp用滚动数组
void dfs(int lm,short dep,short o_n,int now,short &ans){
	if (dep>prime.size()) ans=(ans+lm/now*o_n)%10007;
	    else dfs(lm,dep+1,o_n,now,ans),dfs(lm,dep+1,-o_n,now*prime[dep-1],ans);//容斥
}
signed main(){
	scanf("%d%d%d",&n,&m,&k);
	for (rr short i=1;i*i<=k;++i)//首先找出k的约数
	if (k%i==0){
		kdys.push_back(i);
		if (i*i<k) kdys.push_back(k/i);
	}
	sort(kdys.begin(),kdys.end());
	for (rr short i=2;i*i<=k&&k>1;++i)//然后找出k的质约数
	if (k%i==0){
		prime.push_back(i);
		while (k%i==0) k/=i;
	}
	if (k>1) prime.push_back(k);
	for (rr short i=0;i<kdys.size();++i){//找出k的约数的约数(必然也是k的约数)
		rr char flag=65;
		for (rr short j=0;j<=i;++j)
		if (kdys[i]%kdys[j]==0)
		    flag=66,kdys2[i].push_back(j);
	}
	for (rr short i=0;i<kdys.size();++i){//初始化,记录编号
		rk[kdys[i]]=i; rr short ans=0;
		if (m/kdys[i]==0) continue;
		dfs(m/kdys[i],1,1,1,ans);
		dp[i][0]=pre[i]=ans%10007;
	}
    for (rr short i=2;i<=n;++i,t1^=1)
    for (rr short j=0;j<kdys.size();++j){
    	rr short tot=0; if (!kdys2[j].size()) continue;//基本不可能,但是为了好看
    	for (rr short k=0;k<(kdys2[j].size()&15);++k) tot=(tot+answer(k))%10007;//循环展开
		for (rr short k=(kdys2[j].size()&15);k<kdys2[j].size();k+=16){
    		tot=(tot+answer(k)+answer(k+1))%10007;
    		tot=(tot+answer(k+2)+answer(k+3))%10007;
    		tot=(tot+answer(k+4)+answer(k+5))%10007;
    		tot=(tot+answer(k+6)+answer(k+7))%10007;
    		tot=(tot+answer(k+8)+answer(k+9))%10007;
    		tot=(tot+answer(k+10)+answer(k+11))%10007;
    		tot=(tot+answer(k+12)+answer(k+13))%10007;
    		tot=(tot+answer(k+14)+answer(k+15))%10007;
		}
		//其实就是for (rr short k=0;k<kdys2[j].size();++k) tot=(tot+answer(k))%10007;
		dp[j][t1]=tot;
	}
	return !printf("%d",(dp[kdys.size()-1][t1^1]%10007+10007)%10007);//输出答案
}

后续

沉迷OI,日渐消瘦虚胖

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值