题解 黑客(续)

传送门

相对简单的数位DP,需要高精

  • 需要注意的是类似数位DP这样的DP用记搜实现状态数可能会比刷表少很多
  • 对于类似「为啥 1<<2 等于1啊」这样的问题,康康你存的类型是不是int,尤其注意是不是开成bool了

于是令 \(dp[i][j]\) 为由低位到高位考虑到第 \(i\) 位,当前不能再选的数的集合为 \(s\) 时的方案数
一开始定义时由高向低,已经选的数集合为 \(s\),但不方便记搜
转移枚举当前还能选的数转移

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 510
#define ll long long
#define pb push_back
#define int128 __int128
#define int long long
#define ull unsigned long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}
char sta[N]; int top;
inline void write(int128 t) {
	top=0;
	do {sta[++top]=char('0'+t%10); t/=10;} while (t);
	while (top) putchar(sta[top--]);
	printf("\n");
}
const ull base=1000000000;
struct bigint{
	ull a[120]; int siz;
	bigint(){siz=1; memset(a, 0, sizeof(a));}
	bigint(ll t){siz=1; memset(a, 0, sizeof(a)); *this=t;}
	inline ull& operator [] (int t) {return a[t];}
	void put() {printf("%lld", a[siz]); for (int i=siz-1; i>0; --i) printf("%09lld", a[i]); printf("\n");}
	inline void operator = (ll t) {
		siz=0;
		do {
			++siz;
			a[siz]=t%base;
			t/=base;
		} while (t) ;
	}
	inline bigint operator * (bigint b) {
		bigint ans;
		// cout<<siz<<' '<<b.siz<<endl;
		// exit(0);
		for (int i=1; i<=siz; ++i) {
			for (int j=1; j<=b.siz; ++j) {
				// cout<<"ij: "<<i<<' '<<j<<endl;
				// exit(0);
				ans[i+j-1]+=a[i]*b[j];
				ans[i+j]+=ans[i+j-1]/base;
				ans.siz=max(ans.siz, i+j-1);
				if (ans[i+j-1]/base) ans.siz=max(ans.siz, i+j);
				ans[i+j-1]%=base;
			}
		}
		// exit(0);
		for (int i=1; i<=ans.siz; ++i) {
			ans[i+1]+=ans[i]/base;
			if (ans[i]/base) ans.siz=max(ans.siz, i+1);
			ans[i]%=base;
		}
		return ans;
	}
	inline bigint operator * (ll t) {
		bigint ans; ans=t;
		ans=ans*(*this);
		return ans;
	}
	inline bigint operator + (bigint b) {
		bigint ans;
		int lim=max(siz, b.siz);
		for (int i=1; i<=lim; ++i) {
			ans[i]+=a[i]+b[i];
			ans[i+1]+=ans[i]/base;
			ans.siz=max(ans.siz, i);
			if (ans[i]/base) ans.siz=max(ans.siz, i+1);
			ans[i]%=base;
		}
		return ans;
	}
	inline bigint operator + (ll t) {
		bigint ans; ans=t;
		ans=ans+(*this);
		return ans;
	}
	inline bool operator ! () {return siz<=1&&a[1]==0;}
};
inline bigint qpow(bigint a, int b) {bigint ans; ans=1ll; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}

int n, m, k;
vector<int> ban[N];

namespace force{
	int s[N];
	int128 ans1, ans2;
	void check() {
		ll tem=0;
		for (int i=1; i<=n; ++i) tem=(tem<<3)+(tem<<1)+s[i];
		++ans1; ans2+=tem;
	}
	void dfs(int u) {
		if (u>n) {check(); return ;}
		for (int i=1; i<=k; ++i) {
			for (auto it:ban[i]) for (int j=1; j<u; ++j) if (it==s[j]) goto jump;
			s[u]=i;
			dfs(u+1);
			jump: ;
		}
	}
	void solve() {
		dfs(1);
		// printf("%lld\n%lld\n", ans1, ans2);
		write(ans1); write(ans2);
		exit(0);
	}
}

namespace task1{
	inline int128 qpow(int128 a, int b) {int128 ans=1; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}
	void solve() {
		write(qpow(k, n));
		int128 ans=0, tem=qpow(k, n-1), lst=k*(k+1)/2;
		for (int i=1; i<=n; ++i) {
			ans=ans+tem*lst;
			lst*=10;
		}
		write(ans);
		exit(0);
	}
}

namespace task2{
	void solve() {
		bigint k2; k2=1ll*k;
		bigint tem=qpow(k2, n); tem.put();
		bigint ans, lst; ans=0, lst=0;
		tem=qpow(k2, n-1);
		// tem=tem*tem;
		for (int i=1; i<=k; ++i) lst=lst+i;
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			ans=ans+tem*lst;
			lst=lst*10;
		}
		ans.put();
		exit(0);
	}
}

namespace task{
	int tot, disable[10];
	bigint f[510][1<<9], g[510][1<<9], ans, p[510], tem;
	bool able[1<<9][10], vis[510][1<<9];
	void dfs(int u, int s) {
		if (vis[u][s]) return ;
		if (u>n) {f[u][s]=1; g[u][s]=0; vis[u][s]=1; return ;}
		for (int i=0; i<k; ++i) if (!(s&(1<<i))) {
			int v=u+1, t=s|disable[i];
			dfs(v, t);
			f[u][s]=f[u][s]+f[v][t];
			g[u][s]=g[u][s]+g[v][t]*10+f[v][t]*(i+1);
		}
		vis[u][s]=1;
	}
	void solve() {
		// cout<<double(sizeof(f)*2)/1024/1024<<endl;
		#if 0
		for (int i=0; i<n; ++i) {
			for (int s=0; s<lim; ++s) if (!(!f[i][s])) {
				for (int j=0; j<k; ++j) if (able[s][j]) {
					f[i+1][s|(1<<j)]=f[i+1][s|(1<<j)]+f[i][s];
				}
			}
		}
		for (int s=0; s<lim; ++s) ans=ans+f[n][s];
		ans.put();
		p[0]=1;
		for (int i=1; i<=n; ++i) p[i]=p[i-1]*10;
		for (int i=0; i<k; ++i) g[1][1<<i]=p[n-1]*(i+1);
		for (int i=1; i<n; ++i) {
			// cout<<"i: "<<i<<endl;
			for (int s=0; s<lim; ++s) if (!(!g[i][s])) {
				tem=p[n-i-1]*f[i][s];
				for (int j=0; j<k; ++j) if (able[s][j]) {
					g[i+1][s|(1<<j)]=g[i+1][s|(1<<j)]+g[i][s]+tem*(j+1);
					++tot;
				}
			}
		}
		ans=0;
		for (int s=0; s<lim; ++s) ans=ans+g[n][s];
		ans.put();
		#else
		for (int i=0; i<k; ++i) for (auto it:ban[i+1]) disable[i]|=1<<(it-1);
		dfs(1, 0);
		f[1][0].put(); g[1][0].put();
		// cout<<f[1][0]<<' '<<g[1][0]<<endl;
		#endif
		// cout<<"tot: "<<tot<<endl;
	}
}

signed main()
{
	freopen("hacker2.in", "r", stdin);
	freopen("hacker2.out", "w", stdout);

	n=read(); m=read(); k=read();
	for (int i=1,a,b; i<=m; ++i) {
		a=read(); b=read();
		ban[b].pb(a);
	}
	// force::solve();
	// task1::solve();
	// if (!m) task2::solve();
	// else force::solve();
	task::solve();

	return 0;
}
posted @ 2021-10-05 18:46  Administrator-09  阅读(21)  评论(2编辑  收藏  举报