F Roads
某个国家有石头路和烂泥路,石头路恰好是生成树,维护路自然是花钱的,现在希望通过修改路的维护费用使得石头路是最小生成树(可以不是唯一的MST),目标是总的修改量最小,要求输出方案。
设石头路的修改后权值为w[i]-d[i]
烂泥路的修改后权值为w[i]+d[i]
对于1条烂泥路x,恰对应了MST中一条链,显然它权值要大于上面的任意一条边y。
wx+dx≥wy−dy
dx+dy≥wy−wx
原问题变为2分图最小权覆盖(Minimum Weighted Cover)
这可以用KM解决。
#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int>
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
For(j,m-1) cout<<a[i][j]<<' ';\
cout<<a[i][m]<<endl; \
}
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
#define MAXN 500
int fa[MAXN],wfa[MAXN],idefa[MAXN];
vi e[MAXN],wei[MAXN],id[MAXN];
int dep[MAXN];
void dfs(int x,int f,int d) {
fa[x]=f;
dep[x]=d;
Rep(i,SI(e[x])) {
int v=e[x][i],w=wei[x][i],idd=id[x][i];
if (v^f){
wfa[v]=w;
idefa[v]=idd;
dfs(v,x,d+1);
}
}
}
int f[MAXN][MAXN];
int u[MAXN],v[MAXN],w[MAXN];
namespace KM{
const int N=405;
const ll inf=~0U>>1;
int n,nl,nr,m,z,py,x,y,i,j,p,lk[N],pre[N];
bool vy[N];
int lx[N],ly[N],d,w[N][N],slk[N];ll ans;
int work(int nl,int nr){ // nl nr w
n=max(nl,nr);
For(i,nl) For(j,nr) w[i][j]=max(0,f[i][j]);
// while(m--)scanf("%d%d%d",&x,&y,&z),w[y][x]=max(w[y][x],z);
for(i=1;i<=n;i++)for(j=1;j<=n;j++)lx[i]=max(lx[i],w[i][j]);
for(i=1;i<=n;i++){
for(j=1;j<=n;j++)slk[j]=inf,vy[j]=0;
for(lk[py=0]=i;lk[py];py=p){
vy[py]=1;d=inf;x=lk[py];
for(y=1;y<=n;y++)if(!vy[y]){
if(lx[x]+ly[y]-w[x][y]<slk[y])slk[y]=lx[x]+ly[y]-w[x][y],pre[y]=py;
if(slk[y]<d)d=slk[y],p=y;
}
for(y=0;y<=n;y++)if(vy[y])lx[lk[y]]-=d,ly[y]+=d;else slk[y]-=d;
}
for(;py;py=pre[py])lk[py]=lk[pre[py]];
}
for(i=1;i<=n;i++)ans+=lx[i]+ly[i];
// printf("%lld\n",ans);
// for(i=1;i<=nl;i++)printf("%d ",w[lk[i]][i]?lk[i]:0);
}
}
int n,m;
void prekm(int x,int y,int p) {
if (dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y]) {
f[idefa[x]][p]=-w[p+n-1]+wfa[x];
x=fa[x];
}
while(x^y) {
f[idefa[x]][p]=-w[p+n-1]+wfa[x];
f[idefa[y]][p]=-w[p+n-1]+wfa[y];
x=fa[x];
y=fa[y];
}
}
int main()
{
freopen("roads.in","r",stdin);
freopen("roads.out","w",stdout);
n=read(),m=read();
For(i,n-1) {
int u=read(),v=read(),w=read();
e[u].pb(v);e[v].pb(u);
wei[u].pb(w);wei[v].pb(w);
id[u].pb(i); id[v].pb(i);
::w[i]=w;::u[i]=u;::v[i]=v;
}
dfs(1,0,1);
MEM(f)
Fork(i,n,m) {
u[i]=read(),v[i]=read();w[i]=read();
prekm(u[i],v[i],i-n+1);
}
KM::work(n-1,m-n+1);
For(i,n-1) {
printf("%d\n",w[i]-KM::lx[i]);
}
Fork(i,n,m) {
printf("%d\n",w[i]+KM::ly[i-n+1]);
}
return 0;
}
H
一张票有N*M的黑白格子,可以卷成圆柱(cylinder)再卷成环,问这样操作后依然不同构的票有多少种。(n,m<=20)
根据伯恩赛德定理,等价类个数=置换集合中的每个置换不动点个数C(f)的平均值.
当n!=m时,有左移,上移,转180度,3种置换(互不影响)。
等价类个数=2∗n∗m
这题n=m时,还可以旋转90度。
等价类个数=4∗n∗m
#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int>
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) Rep(i,n-1) cout<<a[i]<<' '; cout<<a[n-1]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
For(j,m-1) cout<<a[i][j]<<' ';\
cout<<a[i][m]<<endl; \
}
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int gcd(int a,int b){
return (!b)?a:gcd(b,a%b);
}
struct BigInteger {
typedef unsigned long long LL;
static const int BASE = 100000000;
static const int WIDTH = 8;
vector<int> s;
BigInteger& clean(){while(!s.back()&&s.size()>1)s.pop_back(); return *this;}
BigInteger(LL num = 0) {*this = num;}
BigInteger(string s) {*this = s;}
BigInteger& operator = (long long num) {
s.clear();
do {
s.push_back(num % BASE);
num /= BASE;
} while (num > 0);
return *this;
}
BigInteger& operator = (const string& str) {
s.clear();
int x, len = (str.length() - 1) / WIDTH + 1;
for (int i = 0; i < len; i++) {
int end = str.length() - i*WIDTH;
int start = max(0, end - WIDTH);
sscanf(str.substr(start,end-start).c_str(), "%d", &x);
s.push_back(x);
}
return (*this).clean();
}
BigInteger operator + (const BigInteger& b) const {
BigInteger c; c.s.clear();
for (int i = 0, g = 0; ; i++) {
if (g == 0 && i >= s.size() && i >= b.s.size()) break;
int x = g;
if (i < s.size()) x += s[i];
if (i < b.s.size()) x += b.s[i];
c.s.push_back(x % BASE);
g = x / BASE;
}
return c;
}
BigInteger operator - (const BigInteger& b) const {
assert(b <= *this); // ¼õÊý²»ÄÜ´óÓÚ±»¼õÊý
BigInteger c; c.s.clear();
for (int i = 0, g = 0; ; i++) {
if (g == 0 && i >= s.size() && i >= b.s.size()) break;
int x = s[i] + g;
if (i < b.s.size()) x -= b.s[i];
if (x < 0) {g = -1; x += BASE;} else g = 0;
c.s.push_back(x);
}
return c.clean();
}
BigInteger operator * (const BigInteger& b) const {
int i, j; LL g;
vector<LL> v(s.size()+b.s.size(), 0);
BigInteger c; c.s.clear();
for(i=0;i<s.size();i++) for(j=0;j<b.s.size();j++) v[i+j]+=LL(s[i])*b.s[j];
for (i = 0, g = 0; ; i++) {
if (g ==0 && i >= v.size()) break;
LL x = v[i] + g;
c.s.push_back(x % BASE);
g = x / BASE;
}
return c.clean();
}
BigInteger operator / (const BigInteger& b) const {
assert(b > 0); // ³ýÊý±ØÐë´óÓÚ0
BigInteger c = *this; // ÉÌ:Ö÷ÒªÊÇÈÃc.sºÍ(*this).sµÄvectorÒ»Ñù´ó
BigInteger m; // ÓàÊý:³õʼ»¯Îª0
for (int i = s.size()-1; i >= 0; i--) {
m = m*BASE + s[i];
c.s[i] = bsearch(b, m);
m -= b*c.s[i];
}
return c.clean();
}
BigInteger operator % (const BigInteger& b) const { //·½·¨Óë³ý·¨Ïàͬ
BigInteger c = *this;
BigInteger m;
for (int i = s.size()-1; i >= 0; i--) {
m = m*BASE + s[i];
c.s[i] = bsearch(b, m);
m -= b*c.s[i];
}
return m;
}
// ¶þ·Ö·¨ÕÒ³öÂú×ãbx<=mµÄ×î´óµÄx
int bsearch(const BigInteger& b, const BigInteger& m) const{
int L = 0, R = BASE-1, x;
while (1) {
x = (L+R)>>1;
if (b*x<=m) {if (b*(x+1)>m) return x; else L = x;}
else R = x;
}
}
BigInteger& operator += (const BigInteger& b) {*this = *this + b; return *this;}
BigInteger& operator -= (const BigInteger& b) {*this = *this - b; return *this;}
BigInteger& operator *= (const BigInteger& b) {*this = *this * b; return *this;}
BigInteger& operator /= (const BigInteger& b) {*this = *this / b; return *this;}
BigInteger& operator %= (const BigInteger& b) {*this = *this % b; return *this;}
bool operator < (const BigInteger& b) const {
if (s.size() != b.s.size()) return s.size() < b.s.size();
for (int i = s.size()-1; i >= 0; i--)
if (s[i] != b.s[i]) return s[i] < b.s[i];
return false;
}
bool operator >(const BigInteger& b) const{return b < *this;}
bool operator<=(const BigInteger& b) const{return !(b < *this);}
bool operator>=(const BigInteger& b) const{return !(*this < b);}
bool operator!=(const BigInteger& b) const{return b < *this || *this < b;}
bool operator==(const BigInteger& b) const{return !(b < *this) && !(b > *this);}
};
ostream& operator << (ostream& out, const BigInteger& x) {
out << x.s.back();
for (int i = x.s.size()-2; i >= 0; i--) {
char buf[20];
sprintf(buf, "%08d", x.s[i]);
for (int j = 0; j < strlen(buf); j++) out << buf[j];
}
return out;
}
istream& operator >> (istream& in, BigInteger& x) {
string s;
if (!(in >> s)) return in;
x = s;
return in;
}
BigInteger p2[410];
#define MAXN (10000)
int a[MAXN];
void pre(int n){
Rep(i,n) a[i]=i;
}
bool vis[MAXN];
BigInteger polya(int k,int *a,int n) { //Öû»²»¶¯µã¸öÊý
Rep(i,n) vis[i]=0;
int p=0;
Rep(i,n) if (!vis[i]) {
int j=i;
do {
vis[j]=1;
j=a[j];
}while(!vis[j]);
++p;
}
return p2[p];
}
int a2[MAXN];
int main()
{
freopen("tickets.in","r",stdin);
freopen("tickets.out","w",stdout);
int n=read(),m=read();
pre(n*m);
p2[1]=2;
Fork(i,2,n*m) p2[i]=p2[i-1]*2;
BigInteger ans=0;
pre(n*m);
Rep(i2,n) {
Rep(j2,m) {
Rep(i,n) Rep(j,m)
a[i*m+j] = (i2+i)%n*m+(j+j2)%m;
ans+=polya(2,a,n*m);
if (n==m) {
Rep(i,n) Rep(j,m) {
a2[i*m+j] = a[(n-j-1)*m+i];
}
ans+=polya(2,a2,n*m);
}
Rep(i,n) Rep(j,m) {
a[(n-i-1)*m+(m-j-1)] = (i2+i)%n*m+(j+j2)%m;
}
ans+=polya(2,a,n*m);
if (n==m) {
Rep(i,n) Rep(j,m) {
a2[i*m+j] = a[(n-j-1)*m+i];
}
ans+=polya(2,a2,n*m);
}
}
}
ans/=(n*m*2);
if (n==m) ans/=2;
cout<<ans<<endl;
return 0;
}