社区讨论
这种题瞪不出势能函数时的暴力解决方法
CF1025GCompany Acquisitions参与者 1已保存回复 1
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mjp3crg0
- 此快照首次捕获于
- 2025/12/28 10:09 2 个月前
- 此快照最后确认于
- 2025/12/31 14:05 2 个月前
可以考虑高斯消元。代码放在最后。
值得注意的是,势能函数的设计不是唯一的,因此高消会出现自由元,导致所有计算都废掉了。解决的办法是钦定一个元素的值,然后再消。比如这里我们钦定 。然后如果不满足第二个条件(终态唯一且最小)就重新设定,这一部分的设定既然是小数据就可以直观感受势能值了。
注:一般来说钦定的值都要是开头的容易设置的值,比如 啥的。
CPP#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = (a), i##ABRACADABRA = (b); i <= i##ABRACADABRA; i++)
#define drep(i, a, b) for (int i = (a), i##ABRACADABRA = (b); i >= i##ABRACADABRA; i--)
using namespace std;
using ll = long long;
constexpr ll mod=1e9+7;
ll qpow(ll x, ll y) {
if (y < 0)
y += mod - 1 + mod - 1;
if (x == mod - 1)
return y & 1 ? mod - 1 : 1;
ll res = 1;
for (; y; y >>= 1) {
if (y & 1) {
res *= x;
res %= mod;
}
x *= x;
x %= mod;
}
return res;
}
int n,tot;
ll a[505][505];
void gauss(int m){
rep(i,1,n){
int p=0;
rep(j,i,m)if (a[j][i]){
p=j;
break;
}
if (!p)continue;
else if (p!=i){
rep(j,1,n+1)swap(a[i][j],a[p][j]);
}
rep(j,i+1,m)if (a[j][i]){
ll iv=qpow(a[i][i],-1);
drep(k,n+1,i){
a[j][k]+=mod-a[j][i]*iv%mod*a[i][k]%mod;
a[j][k]%=mod;
// cout<<a[j][k]<<'\n';
}
}
}
drep(i,n,1){
rep(j,i+1,n){
(a[i][n+1]+=mod-a[j][n+1]*a[i][j]%mod)%=mod;
a[i][j]=0;
}
(a[i][n+1]*=qpow(a[i][i],-1))%=mod;
a[i][i]=1;
}
}
int main() {
scanf("%d",&n),++n;
rep(x,0,n-2)rep(y,0,n-2){
// 2(f(x)+f(y)-1)=(x+y)f(0)+f(x+1)+f(y+1)
// => 2f(x)+2f(y)-(x+y)f(0)-f(x+1)-f(y+1)=2
++tot;
a[tot][1]=mod-x-y;
a[tot][x+1]+=2;
a[tot][y+1]+=2;
a[tot][x+2]+=mod-1;
a[tot][y+2]+=mod-1;
a[tot][n+1]+=2;
a[tot][1]%=mod;
a[tot][x+2]%=mod;
a[tot][y+2]%=mod;
}
// Let f(0)=0
a[++tot][1]=1;
gauss(tot);
rep(i,1,n)cout<<a[i][n+1]<<" \n"[i==n||i%3==0];
return 0;
}
回复
共 1 条回复,欢迎继续交流。
正在加载回复...