20250728总结
除了改题以外没干啥事,是不是废了/ll
P3643 [APIO2016] 划艇
动态规划:13 组合计数:9我用脚填的数值
神仙题目。
想到了离散化+前缀和,可惜组计没推出来,然后写了个暴力。
一个比较好想到的dp:设
稍加思考可以想到前缀和优化,即设 当然你还可以上二维前缀和,强行优化到
不过
首先
首先我们新
一部分是划艇数
另一部分则是划艇数
但之前某一天里的总结写到过,这种取的数必须递增的情况可以把取的数放桶里,然后就变成了排列组合问题,此处同理。
当我们多开
根据乘法原理,两部分合并后的答案为:
因为
int main(){
n = read();
for(i = 1; i <= n; i++){
a[i] = read(),b[i] = read() + 1;
lsh[++m] = a[i],lsh[++m] = b[i];
}
inv[1] = 1;
for(i = 2; i <= n; i++){
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
sort(lsh + 1,lsh + m + 1);
m = unique(lsh + 1,lsh + m + 1) - lsh - 1;
for(i = 1; i <= n; i++){
a[i] = lower_bound(lsh + 1,lsh + m + 1,a[i]) - lsh;
b[i] = lower_bound(lsh + 1,lsh + m + 1,b[i]) - lsh;
}
c[0] = 1;
f[0][0] = g[0][0] = 1;
for(j = 1; j < m; j++){
int1 len = lsh[j + 1] - lsh[j];
for(i = 1; i <= n; i++){
c[i] = c[i - 1] * (i + len - 1) % mod * inv[i] % mod;
}
for(i = 0; i <= n; i++){
if(a[i] <= j && j < b[i]){
int1 _m = 1;
for(k = i - 1; k >= 0; k--){
f[i][j] = (f[i][j] + c[_m] * g[k][j - 1]) % mod;
if(a[k] <= j && j < b[k]){
_m++;
}
}
}
g[i][j] = (g[i][j - 1] + f[i][j]) % mod;
}
}
for(i = 1; i <= n; i++){
ans = (ans + g[i][m - 1]) % mod;
}
pe(ans);
return 0;
}
P3043 [USACO12JAN] Bovine Alliance G
哇好水的蓝题(((
你个fvv,四十多分钟才想出来
首先
假设一个连通块有
- 若
x < y ,显然无解,答案为0 。 - 若
x = y ,说明有环。环上某边两端的点选择随意,但剩下点的选择会因此固定,所以答案为C_2^1 = 2 。 - 若
x > y ,此时只有可能x - 1 = y ,所以可以选择一个点不选边,而剩下的点的选择会因此固定,所以答案为x 。
各部分答案相乘即可。
void add_edge(int1 x,int1 y){
nex[++bs] = hea[x],hea[x] = bs,to[bs] = y,in[y]++;
return ;
}
int1 dfs(int1 x){
already++;
int1 cnt = in[x];
vis[x] = 1;
for(int1 i = hea[x]; i; i = nex[i]){
int1 y = to[i];
if(!vis[y]){
cnt += dfs(y);
}
}
return cnt;
}
int main(){
n = read(),m = read();
for(i = 1; i <= m; i++){
int1 x = read(),y = read();
add_edge(x,y),add_edge(y,x);
}
ans = 1;
for(i = 1; i <= n; i++){
if(!vis[i]){
int1 y = dfs(i) >> 1;
int1 x = already - last;
if(x < y){
putchar('0');
return 0;
}else if(x == y){
ans = (ans << 1) % mod;
}else{
ans = ans * x % mod;
}
last = already;
}
}
pe(ans);
return 0;
}
P4160 [SCOI2009] 生日快乐
初看不好做,然而实际上因为
double cut(double x,double y,int1 n){
if(n == 1){
return max(x,y) / min(x,y);
}
double ans = INF;
double _x = x / n,_y = y / n;
for(int1 i = 1,j = n - 1; i < n; i++,j--){//枚举两边切的份数
ans = min(ans,max(cut(x,_y * i,i),cut(x,_y * j,j)));
ans = min(ans,max(cut(_x * i,y,i),cut(_x * j,y,j)));
}
return ans;
}
int main(){
x = read(),y = read(),n = read();
printf("%.6lf\n",cut(x,y,n));
return 0;
}
P9751 [CSP-J 2023] 旅游巴士
这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?这是绿?
这我场切个己卯啊/ll
发现
但问题来了:
死盯样例可以发现我们可以在起点等
int main(){
n = read(),m = read(),k = read();
for(i = 1; i <= m; i++){
int1 x = read(),y = read(),z = read();
add_edge(x,y,z);
}
for(i = 1; i <= n; i++){
for(j = 0; j < k; j++){
dis[i][j] = INF;
}
}
dis[1][0] = 0;
q.push(make_pair(0,1));
while(!q.empty()){
int1 now = q.top().second,bzd = q.top().first;
q.pop();
if(!vis[now][bzd % k]){
vis[now][bzd % k] = 1;
for(i = hea[now]; i; i = nex[i]){
int1 y = to[i],w = bzd + 1 + max(0,(t[i] - bzd + k - 1) / k * k);
if(dis[y][w % k] > w){
dis[y][w % k] = w;
q.push(make_pair(w,y));
}
}
}
}
if(dis[n][0] == INF){
pe(-1);
}else{
pe(dis[n][0]);
}
return 0;
}