省选模拟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;
}