省选模拟17

A. 进制转换

可以把进制转换看成是一个解一个式子

每一项的系数都在 \(0\) 到 \(9\)

考虑 \(b\) 较大时的情况,最高次的值要远大于其他值

于是只考虑这一项带来的限制

\(a_mb^m\leq y \leq a_mb^m+9\times \frac{b^m-1}{b-1}\)

根据这个式子可以解出 \(b\) 的两个取值的范围是,从大到下一次枚举,暴力检验就行

\(b\) 较小时也可以暴力检验

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
inline void write(int x){
	static int stk[42],top;
	while(x) stk[++top]=x%10,x/=10;
	while(top) putchar(stk[top--]+'0');
	putchar('\n');
}
int T,y,lim,b;
int calc(int x,int b){
	int res=0,p=1;
	while(x){if(x%b>9) return -1;res+=x%b*p;x/=b;p*=10;}
	return res;
}
inline void solve(){
	y=read(),lim=read();
	for(int i=log10l(lim);i<=8;i++) for(int j=1;j<=9;j++) for(int r=powl(1.0L*y/j,1.0L/i),l=powl(1.0L*(y-9*(powl(r,i)-1)/(r-1))/(j),1.0L/i);r>=l;r--){
		if(lim<=calc(y,r)){printf("%lld\n",r);return ;}
	}
	for(int i=100;i;i--) if(lim<=calc(y,i)){printf("%lld\n",i);return ;}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("number.in","r",stdin);
	freopen("number.out","w",stdout);
	T=read();while(T--) solve();
	return 0;
}

B. 遇到困难睡大觉

学了退火,加上考场的随机交换能拿 \(80\)

记录最大值和最小值的位置,每次随机一个位置和最大或最小值交换

然后套上退火就行

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define lson rt<<1
#define rson rt<<1|1
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,k,ans=-inf,mx,mn;
struct data{
	int a,b;
	inline bool operator<(const data &B)const{return a==B.a?b>B.b:a>B.a;}
	inline bool operator==(const data &B)const{return a==B.a||b==B.b;}
}L[100010];
inline bool chk(){double t=1.0*clock()/CLOCKS_PER_SEC;return t<2.0;}
mt19937 rd(time(0));
struct Seg{int mn,mx,mnp,mxp;}st[100010*4];
inline void pushup(int rt){
	st[rt].mn=min(st[lson].mn,st[rson].mn);
	st[rt].mx=max(st[lson].mx,st[rson].mx);
	if(st[rt].mn==st[lson].mn) st[rt].mnp=st[lson].mnp;else st[rt].mnp=st[rson].mnp;
	if(st[rt].mx==st[lson].mx) st[rt].mxp=st[lson].mxp;else st[rt].mxp=st[rson].mxp;
}
void build(int rt,int l,int r){
	if(l==r) return st[rt].mn=L[l].a+l*k,st[rt].mx=L[l].b+l*k,st[rt].mnp=l,st[rt].mxp=l,void();
	int mid=(l+r)>>1;
	build(lson,l,mid);
	build(rson,mid+1,r);
	pushup(rt);
}
void upd(int rt,int l,int r,int pos){
	if(l==r) return st[rt].mn=L[l].a+l*k,st[rt].mx=L[l].b+l*k,void();
	int mid=(l+r)>>1;
	if(pos<=mid) upd(lson,l,mid,pos);
	else upd(rson,mid+1,r,pos);
	pushup(rt);
}
inline void SA(){
	int nans=-inf;
	double T=1000000;int now,del,typ,p1,p2;
	random_shuffle(L+1,L+1+n);build(1,1,n);nans=st[1].mn-st[1].mx;
	while(T>1e-12){
		typ=rd()%2,p2=rd()%n+1;
		if(typ) p1=st[1].mnp;else p1=st[1].mxp;if(L[p1]==L[p2]){T*=0.99997;continue;}
		swap(L[p1],L[p2]);upd(1,1,n,p1);upd(1,1,n,p2);
		now=st[1].mn-st[1].mx;del=now-nans;
		nans=max(nans,now);
		if(now!=nans&&exp(1.0*del/T)*RAND_MAX<rand()){swap(L[p1],L[p2]);upd(1,1,n,p1);upd(1,1,n,p2);}
		T*=0.99996;
	}
	ans=max(ans,nans);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("sleep.in","r",stdin);
	freopen("sleep.out","w",stdout);
	n=read(),k=read();
	for(int i=1;i<=n;i++) L[i].b=read(),L[i].a=read();sort(L+1,L+1+n);
	build(1,1,n);ans=max(ans,st[1].mn-st[1].mx);
	while(chk()) SA();
	printf("%lld\n",ans);
	return 0;
}

T3

若不考虑 \(a_i\) 的限制,可以用插板法算出 \(n\) 个钥匙放在 \(m\) 个地方的方案数

考虑 \(a_i\) 的限制就可以强制选 \(a_i+1\) 个然后再用容斥搞,需要乘上 \((-1)^{|S|}\) 的系数

带上 \(p_i\) 的权值也很好求

可以用 \(dp\) 来求这个容斥,设 \(f_{i,x,y,t}\) 表示前 \(i\) 个地点,被发现的地点选择容斥的集合大小为 \(x\) 的方案数, \(y\) 为没有被发现的, 选择了 \(t\) 个地点被发现的概率

然后再求解一共有多少种方案就行

求解方案相当与这样一个问题一共 \(n_1+n_2\) 把钥匙放在 \(m_1+m_2\) 个地点

其中前 \(m_1\) 个地点至少放 \(n_1\) 把

暴力可以直接枚举前面多放几把,然后用插板法求方案

用组合意义换种枚举方法,直接枚举第 \(n_1\) 把钥匙放在哪里,然后再插板法求方案

\(\sum\limits_{k=1}^m1\binom{n_1-1+k-1}{n_1-1}\binom{n_2+M-k}{n_2}\)

然后 \(n_1=n-x\) , \(n_2=N-n-y\) 这个根据上面的 \(dp\) 定义求出

对于不同的 \(n_1,n_2\) 预处理出所有组合数就行

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define mod 998244353
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int m,d,N,lim,n,cur,ans;
int a[110],p[110];
int f[2][110][110][110];
int C1[110][110],C2[110][110];
int inv[110];
//C1[i][j] -> C[n-i*d-1+j-1][n-i*d-1(j-1)]
//C2[i][j] -> C[N-n-i*d+m-j][N-n-i*d(m-j)]
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
	return res;
}
inline int C(int n,int m){int res=inv[m];for(int i=n;i>n-m;i--) res=res*i%mod;return res;}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("key.in","r",stdin);
	freopen("key.out","w",stdout);
	inv[0]=1;for(int i=1;i<=100;i++) inv[i]=inv[i-1]*qpow(i,mod-2)%mod;
	m=read(),d=read(),N=read(),n=read();lim=N/d;
	for(int i=1;i<=m;i++) a[i]=(read()+1)/d,p[i]=read();
	for(int i=0;i<=100;i++) for(int j=0;j<=100;j++){
		C1[i][j]=C(n-i*d-1+j-1,j-1);
		C2[i][j]=C(N-n-i*d+m-j,m-j);
	}
	f[0][0][0][0]=1;
	for(int i=0;i<m;i++,cur^=1){
		memset(f[cur^1],0,sizeof(f[cur^1]));
		for(int j=0;j<=lim;j++) for(int k=0;k<=lim;k++) for(int l=0;l<=i;l++) if(f[cur][j][k][l]){
			(f[cur^1][j][k][l+1]+=f[cur][j][k][l]*p[i+1]%mod)%=mod;
			if(j+a[i+1]<=lim) (f[cur^1][j+a[i+1]][k][l+1]+=mod-f[cur][j][k][l]*p[i+1]%mod)%=mod;
			(f[cur^1][j][k][l]+=f[cur][j][k][l]*(1-p[i+1]+mod)%mod)%=mod;
			if(k+a[i+1]<=lim) (f[cur^1][j][k+a[i+1]][l]+=mod-f[cur][j][k][l]*(1-p[i+1]+mod)%mod)%=mod;
		}
	}
	for(int j=0,n1,n2,v;j<=lim;j++) for(int k=0;k<=lim;k++) for(int l=0;l<=m;l++) if(f[cur][j][k][l]){
		n1=n-j*d;n2=N-n-k*d;if(n2<0||n1+n2<0) continue;v=0;
		if(n1<=0){v=C(n1+n2+m-1,m-1);}else{for(int i=1;i<=l;i++) (v+=C1[j][i]*C2[k][i])%=mod;}
		(ans+=v*f[cur][j][k][l]%mod)%=mod;
	}
	printf("%lld\n",(ans+mod)%mod);
	return 0;
}
上一篇:判断是否是回文数


下一篇:阿里云安装redis5