2023.11.16
A
*2800。
给出两个点 \(A\),\(B\) 和 \(n\) 个圆,此外还有一个未知的圆 \(O\) 过 \(A,B\) 且不与任意圆相交。问 \(O\) 的最小可能半径。
\(1\le n\le 10^5\),点和半径值域 \([-10^5,10^5]\)。
答案不超过 \(10^{12}\),要求相对或绝对误差 \(\le 10^{-3}\)。
二分一眼假但是放了 \(80\) 分。
B
*3400。
一棵树,边权为小写字母。记 \(f(a,b)\) 为沿着 \(a\) 到 \(b\) 的简单路径写下的字符串。
多次询问,给定 \(q,p\),问 \(\sum_{m\not=q}[f(q,p)>f(q,m)]\)。
\(n,m\le 2\times 10^4\)。\(\mathrm{TL}=7\mathrm{s}\)。
GJOJ 上 \(n,m\le 3\times 10^4\),\(\mathrm{TL}=5\mathrm{s}\)?
数据很三只 \(\log\)。离线后点分治。
C
你怎么知道我做过原题还差点没写出来?
问 \(n\) 个点,\(m\) 条边的满足如下条件的图的数量:
- 图无自环。
- 每个点度数 \(\le 2\)。
- 最大连通块大小恰好为 \(k\)。
答案模 \(10^9+7\)。
\(1\le n,m,k\le 300\)。
用均 \(\le k\) 的情况减去均 \(\le k-1\) 的情况就解决了限制 \(3\)。
容易观察到连通块一定为链或环。
进一步地,\(n\) 个点的本质不同链个数为 \(\dfrac{n!}{2}\)(\(n=1\) 除外),环个数为 \(\dfrac{(n-1)!}{2}\)(\(n=2\) 除外)。
考虑 DP,设 \(f_{i,j}\) 为 \(i\) 个点用了 \(j\) 条边的方案数。
如何不重不漏地计算,可以钦定当前连通块一定包含编号最小的那个节点,剩下的随便选即可。
有转移方程
\(\displaystyle f_{i,j}\cdot \binom{n-o-1}{o-1}\cdot\frac{o!}{2}\rightarrow f_{i+o,j+o-1}\),特判 \(o=1\)。
\(\displaystyle f_{i,j}\cdot \binom{n-o-1}{o-1}\cdot \frac{(n-1)!}{2}\rightarrow f_{i+o,j+o}\),特判 \(o=2\)。
#include<bits/stdc++.h>
#define N 305
#define P 1000000007
using namespace std;
int read(){
int x=0,w=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*w;
}
int C[N][N],fac[N];
const int I2=(P+1)>>1;
void init(int n){
C[0][0]=fac[0]=1;
for(int i=1;i<=n;i++){
C[i][0]=C[i][i]=1,fac[i]=1ll*fac[i-1]*i%P;
for(int j=1;j<i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
}
}
int n,m;
int f[N][N];
int solve(int k){
memset(f,0,sizeof(f));
f[0][0]=1;
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
for(int o=1;o<=k&&i+o<=n;o++){
if(j+o-1<=m)
f[i+o][j+o-1]=(f[i+o][j+o-1]+1ll*f[i][j]*C[n-i-1][o-1]%P*fac[o]%P*(o>1?I2:1))%P;
if(o>1&&j+o<=m)
f[i+o][j+o]=(f[i+o][j+o]+1ll*f[i][j]*C[n-i-1][o-1]%P*fac[o-1]%P*(o>2?I2:1))%P;
}
return f[n][m];
}
int main(){
init(300);
n=read(),m=read();
int k=read();
printf("%d\n",(solve(k)-solve(k-1)+P)%P);
return 0;
}
D
*2400。
Alice 和 Bob 玩游戏,初始有一个数 \(x=0\)。
进行 \(n\) 次操作:
- Alice 选择实数 \(t\in[0,k]\)。
- Bob 可以令 \(x\leftarrow x+t\) 或 \(x\leftarrow x-t\),且必须至少进行 \(m\) 次加操作。
Alice 欲最大化 \(x\),Bob 欲最小化 \(x\),问两人采用最优策略下 \(x\) 最后的值模 \(10^9+7\)。
\(1\le m\le n\le 10^6\),\(1\le k\le 10^9\)。
Bob 使用加操作一定不优,也就是加操作被恰好执行 \(m\) 次。
设 \(f_{i,j}\) 为游戏还剩 \(i\) 轮,Bob 需使用 \(j\) 次加操作时,Alice 能够获得的最大分数(\(n=i,m=j\) 时的答案)。
可以得到 \(f_{i,j}=\min(f_{i-1,j-1}+x,f_{i-1,j}-x)\),当 \(x=\dfrac{f_{i-1,j}-f_{i-1,j-1}}{2}\) 时 \(f_{i,j}\) 取得最大值 \(\dfrac{f_{i-1,j-1}+f_{i-1,j}}{2}\)。
边界值 \(f_{i,0}=0,i\in[0,n]\),\(f_{i,i}=i\times k,i\in[0,m]\)。
时间复杂度 \(O(nm)\),可以通过 *2100 的 Easy Version。
考虑每个 \(f_{i,i}\) 对最终答案的贡献。从 \(f_{i,i}\) 到 \(f_{n,m}\) 进行了 \(n-i\) 次 \(/2\) 操作。
计算 \(f_{i,i}\) 的贡献次数。可以从 \((x,y)\) 走到 \((x+1,y)\) 和 \((x+1,y+1)\),问不经过 \((k,k),k\in[0,n]\) 从 \((i,i)\) 走到 \((n,m)\) 的方案数。
这相当于从 \((i+1,i)\) 出发走到 \((n,m)\) 的方案数,此时就不用管形如 \((k,k)\) 的点了。
发现方案数就是杨辉三角,即 \(f_{i,i}\) 的贡献次数为 \(\dbinom{n-i-1}{m-i}\)。
答案即 \(\displaystyle k\cdot \sum_{i=1}^{m}\frac{i\cdot \binom{n-i-1}{m-i}}{2^{n-i}}\)。特判 \(n=m\) 的情况。
#include<bits/stdc++.h>
#define N 1000010
#define P 1000000007
using namespace std;
int read(){
int x=0,w=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*w;
}
int qpow(int k,int b){
int ret=1;
while(b){
if(b&1)ret=1ll*ret*k%P;
k=1ll*k*k%P,b>>=1;
}
return ret;
}
const int I2=(P+1)>>1;
int fac[N],ifac[N],p2[N];
void init(int n){
fac[0]=ifac[0]=p2[0]=1;
for(int i=1;i<=n;i++)
fac[i]=1ll*fac[i-1]*i%P,p2[i]=1ll*p2[i-1]*I2%P;
ifac[n]=qpow(fac[n],P-2);
for(int i=n-1;i;i--)
ifac[i]=1ll*ifac[i+1]*(i+1)%P;
}
int C(int n,int m){
if(n<0||m<0||n<m)return 0;
return 1ll*fac[n]*ifac[n-m]%P*ifac[m]%P;
}
int n,m,k;
void solve(){
n=read(),m=read(),k=read();
if(n==m){
int ans=1ll*n*k%P;
printf("%d\n",ans);
return;
}
int ans=0;
for(int i=1;i<=m;i++)
ans=(ans+1ll*i*C(n-i-1,m-i)%P*p2[n-i])%P;
ans=1ll*k*ans%P;
printf("%d\n",ans);
}
int main(){
init(1000000);
int T=read();
while(T--)solve();
return 0;
}

浙公网安备 33010602011771号