judge: 牛客node
judge:牛客ios
给你一个n,让你求出\(\sum_{i=1}^{n}\sum_{j=1}^{i}[gcd(i,j)==1]f(j)\)。
其中f(x)表示的是数位和,eg:f(122)=1+2+2=5。c++
一眼能够看出是道反演题,可是仔细想一想发现不是特别好维护,而后给的范围又有点误导,让人觉得能够瞎搞过(实际上真的能够打表过或者容斥过),而后中间耽搁了很长时间,还写了个瞎搞的作法,不过没敢交,最后才发现转换一下就是一道经典的反演题。
首先题目让咱们求的是\(\sum_{i=1}^{n}\sum_{j=1}^{i}[gcd(i,j)==1]f(j)\),咱们须要转换成\(\sum_{i=1}^{n}f(i)\sum_{j=i+1}^{n}[gcd(i,j)==1]\)。
其实只是枚举策略的变换,求的答案仍是同样,只不过第二个公式能够用反演求,并且还比较好求,第一个没有办法用反演作(实际上是我不会)。
至于缘由,咱们须要对第一个公式有足够的了解,第一个公式让咱们求的是全部比当前数小,且与当前数互质的数的数位和。
思惟转换一下,咱们把每一个数单独进行考虑,每一个数对答案产生的贡献就是比它大,且与它互质的数的个数乘以这个数的数位和(就是转换后的公式)。
至于第二个公式怎么求,能够参考我写的一篇题解,这个题让咱们求的就是前半部分,只不过数位和变成了数位乘。app
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (int i = (s); i <= (t); i++) #define RP(i,t,s) for (int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 1e6+7; int n; ll phi[N],mu[N]; int prime[N]; int flag[N]; ll F[N]; ll G[N]; ll Num[N]; int num=0; int f(int x){ int ans=0; while(x) ans+=x%10,x/=10; return ans; } int g(int x){ int ans=1; while(x) ans*=x%10,x/=10; return ans; } void init(){ phi[1]=1; mu[1]=1; F[1]=G[1]=1; for (int i=2;i<=n;i++){ F[i]=f(i); G[i]=g(i); if (flag[i]==0)//这表明i是质数 { prime[++num]=i; phi[i]=i-1; mu[i]=-1; } for (int j=1;j<=num&&prime[j]*i<=n;j++){ flag[i*prime[j]]=1; if (i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; mu[i*prime[j]]=0; break; } phi[i*prime[j]]=phi[i]*(prime[j]-1),mu[i*prime[j]]=-mu[i]; } } rp(i,1,n) for(int j=i;j<=n;j+=i) Num[i]+=F[j]; } void solve(){ n=read(); init(); ll ans1=0; ll ans2=0; rp(i,1,n){ ll t=0;for(int j=i;j<=n;j+=i) t+=F[j]; ans1+=mu[i]*t*(n/i); } rp(i,1,n) ans2+=F[i]*phi[i]; cout<<ans1-ans2+1<<endl; } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); //debug = 1; #endif time_t beg, end; //if(debug) beg = clock(); solve(); /* if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } */ return 0; }
judge:牛客ui
现有n个苹果,求出可否分给m我的,知足全部人的苹果总数都不同。spa
首先求出知足m我的的苹果数量都不一样的最少苹果数。最实惠的方案固然是依次拥有1,2,3,...,m-1,m个苹果。须要花费\(\frac{m(m+1)}{2}\)个苹果。至于剩下的苹果,所有交给最后一我的便可,这样就知足了全部人的苹果数都不同。.net
若是苹果总数小于\(\frac{m(m+1)}{2}\),就说明不管怎么分都没法知足每一个人的苹果总数都不同。debug
#include <bits/stdc++.h> using namespace std; inline int read() { int s = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); } return s * f; } void solve() { int n = read(), m = read(); if (n >= m * (m + 1) / 2) puts("possible"); else puts("impossible"); } int main() { int T = read(); while (T--) solve(); return 0; }
judge:牛客code
定义一个合法的序列为序列里的每一个元素都出现偶数次。blog
给定一个有n个元素的序列,序列元素最多有21种,编号在数值在[0-20],求出合法序列的个数。
维护每一个数字出现次数的前缀和,且咱们只关心数字出现次数的奇偶性,因此咱们只保存 \(0\) 和 \(1\) 两个状态,一个二进制位便可保存一个数字的状态。将 \(21\) 个前缀和的对应位置概括到一块儿,那么一个 \(int\) 类型的整数就可保存一组状态。
当一组状态为 \(t\) 时,维护每组状态出现的次数 \(num[t]\)。
假设 \(a_i\) 为 \(2\),前一个位置的状态为 \(t\),那么将 \(a_i\) 加入 \(t\),只须要将 \(t\) 中的第 \(i\) 个位置取反,即 \(t=t\oplus(1<<a_i)\)。而后将 \(num[t]=num[t]+1\)。
假设将 \(a_i\) 加入后的状态为 \(t\),则前面有 \(num[t]\) 个位置能够做为起点,第 \(i\) 个位置做为终点,区间内全部元素的出现次数都为偶数。
#include <bits/stdc++.h> #define _for(i, a) for(int i = 0, lennn = (a); i < lennn; ++i) #define _rep(i, a, b) for(int i = (a), lennn = (b); i <= lennn; ++i) using namespace std; typedef long long LL; const int maxn = 100005; const int maxm = 5000005; const int inf = 0x3f3f3f3f; inline int read() { int x(0), f(1); char ch(getchar()); while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int n; int mp[maxm]; void sol() { int t = 0; int ans = 0; ++mp[t]; _rep(i, 1, n) { int x = read(); t ^= (1 << x); ans += mp[t]; ++mp[t]; } printf("%d\n", ans); } int main() { n = read(); sol(); return 0; }
judge:牛客
题意不详...
队友一眼看出答案是 \((m+1)^n\)...
#include <bits/stdc++.h> #define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i) #define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i) using namespace std; typedef long long LL; const int mod = 998244353; inline int read() { int x(0), f(1); char ch(getchar()); while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } LL quickPow(LL x, LL n, LL mod) { LL ans = 1; while(n) { if(n & 1) ans *= x, ans %= mod; x *= x, x %= mod; n >>= 1; } return ans; } int main() { LL n = read(), m = read(); printf("%lld\n", quickPow(m + 1, n, mod)); return 0; }
judge:牛客
给你一个每一个元素都互不相同的长度为 \(n\) 的序列.
定义两种操做:
考虑分块维护每一个块的最小值.
当执行操做1时, 令 \(a_x=y\), 同时从新计算 \(a_x\) 所在的块的最小值.
当执行操做2时, 分别找出左右两边连续大于等于 \(a_x\) 的元素的个数, 例如134562
中4左右分别有1和2个不小于4的元素. 那么能够计算出包含4的子串的数目为 \(1+2+1\times 2+1=6\), 当左边有 \(cl\) 个元素,右边有 \(cr\) 个元素时,包含 \(a_x\) 的字串的数目为 \(cl+cr+cl\times cr+1\).
线段树维护区间最小值。
当执行操做 \(1\) 时,\(update\) 执行更新。
当执行操做 \(2\) 时,分别找出 \([1,x-1]\) 和 \([x+1,n]\) 中距离 \(x\) 最近的最小值的位置,也就是在 \([1,x-1]\) 中找到最靠右的小于 \(a[x]\) 的值的位置,在 \([x+1,n]\) 中找出最靠左的小于 \(a[x]\) 的值的位置。
当咱们查找 \([1,x-1]\) 中最靠右的小于 \(a[x]\) 的值时,应首先检查右儿子最小值是否小于 \(a[x]\),若是小于说明右儿子区间有可能有答案。
之因此说“有可能有答案”是由于线段树每次查找的区间 \([beg,end]\) 和咱们想要找的区间 \([l,r]\) 不必定是重合的,因此就算 \(T[node]\) 小于 \(a[x]\),也仅仅说明是 \([beg,end]\) 区间内有小于 \(a[x]\) 的值,而不是 \([l,r]\) 区间内。当最小值出如今 \(end\) 前面,\(r\) 后面时,只查找右儿子显然会犯错。
更合理的作法是每次查找先判断当前区间的最小值是否大于 \(a[x]\)。而后根据上面的要求查找右儿子,若是右儿子找到了合法的答案,那么左儿子就不必再访问了。若是右儿子没有找到合法的答案,那就须要再找左儿子。
查找 \([x+1,n]\) 同理。
这样单次查询就能直接搜出答案。时间复杂度 \(O(nlogn)\)。
答案是 \(cl+cr+cl\times cr+1\)。
线段树维护区间最小值。
直接二分左右边界,查询区间最小值检验。
时间复杂度相比“线段树解法1”多了个 \(logn\),时间复杂度 \(O(nlog^2n)\)。
#include <bits/stdc++.h> #define _for(i, a) for(LL i = 0, lennn = (a); i < lennn; ++i) #define _rep(i, a, b) for(LL i = (a), lennn = (b); i <= lennn; ++i) using namespace std; typedef long long LL; const LL maxn = 100005; inline LL read() { LL x(0), f(1); char ch(getchar()); while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } LL a[maxn], k[maxn], len; LL n, m; LL getN(LL pos) { return (pos - 1) / len + 1; } void init() { len = sqrt(n) + 1; len = min(len, n); } LL getLValOfThis(LL pos) { LL nu = getN(pos); for(LL i = pos - 1; i > (nu - 1) * len; --i) if(a[i] < a[pos]) return i; return -1; } LL getRValOfThis(LL pos) { LL nu = getN(pos); for(LL i = pos + 1; i <= nu * len; ++i) if(a[i] < a[pos]) return i; return -1; } LL getLVal(LL pos) { LL nu = getN(pos); for(LL i = nu - 1; i > 0; --i) if(k[i] < a[pos]) return i; return -1; } LL getRVal(LL pos) { LL nu = getN(pos), mn = getN(n); for(LL i = nu + 1; i <= mn; ++i) if(k[i] < a[pos]) return i; return -1; } void sol() { init(); _rep(i, 1, n) a[i] = read(); LL mn = getN(n); _rep(i, 1, mn) k[i] = LLONG_MAX; _rep(i, 1, n) k[getN(i)] = min(k[getN(i)], a[i]); _for(i, m) { LL op = read(); if(op == 1) { LL x = read(), val = read(); LL nu = getN(x); a[x] = val; k[nu] = LLONG_MAX; for(LL i = (nu - 1) * len + 1; i <= nu * len; ++i) k[nu] = min(k[nu], a[i]); } else { LL pos = read(); LL l = pos - 1, r = pos + 1; LL cl = 0, cr = 0; LL LThis = getLValOfThis(pos); if(LThis != -1) cl = pos - LThis - 1; // 本块内找到 else { // 本块内未找到,从下一块开始找 LL nu = getLVal(pos); if(nu == -1) cl = pos - 1; // 左边没有比a[pos]更小的 else { // 左边有比a[pos]更小的 cl = pos - nu * len - 1; for(LL i = min(pos - 1, nu * len); i > 0 && a[i] > a[pos]; --i) { cl = pos - i; } } } LL RThis = getRValOfThis(pos); if(RThis != -1) cr = RThis - pos - 1; // 本块内找到 else { // 本块内未找到,从下一块开始找 LL nu = getRVal(pos); if(nu == -1) cr = n - pos; // 右边没有比a[pos]更小的 else { // 右边有比a[pos]更小的 cr = (nu - 1) * len - pos; for(LL i = max(pos + 1, (nu - 1) * len + 1); i <= n && a[i] > a[pos]; ++i) { cr = i - pos; } } } LL ans = cl + cr + cl * cr + 1; printf("%lld\n", ans); } } } int main() { n = read(), m = read(); sol(); return 0; }
#include <bits/stdc++.h> #define _for(i, a) for(int i = 0, lennn = (a); i < lennn; ++i) #define _rep(i, a, b) for(int i = (a), lennn = (b); i <= lennn; ++i) using namespace std; typedef long long LL; const int maxn = 100005; inline LL read() { LL x(0), f(1); char ch(getchar()); while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int n, m; LL a[maxn]; LL T[maxn << 2]; void build(int node, int beg, int end) { if (beg == end) { T[node] = a[beg]; return; } int mid = (beg + end) >> 1; build(node << 1, beg, mid); build(node << 1 | 1, mid + 1, end); T[node] = min(T[node << 1], T[node << 1 | 1]); } void update(int node, int beg, int end, int pos, LL val) { if(beg == end) { T[node] = val; return; } int mid = (beg + end) >> 1; if(pos <= mid) update(node << 1, beg, mid, pos, val); else update(node << 1 | 1, mid + 1, end, pos, val); T[node] = min(T[node << 1], T[node << 1 | 1]); } LL queryl(int node, int beg, int end, int l, int r, LL val) { if(T[node] > val) return 0; if (beg == end) return beg; LL ans = 0; int mid = (beg + end) >> 1; if(mid < r && T[node << 1 | 1] < val) ans = queryl(node << 1 | 1, mid + 1, end, l, r, val); if(mid >= l && ans == 0) ans = queryl(node << 1, beg, mid, l, r, val); return ans; } LL queryr(int node, int beg, int end, int l, int r, LL val) { if(T[node] > val) return n + 1; if (beg == end) return beg; LL ans = n + 1; int mid = (beg + end) >> 1; if(mid >= l && T[node << 1] < val) ans = queryr(node << 1, beg, mid, l, r, val); if(mid < r && ans == n + 1) ans = queryr(node << 1 | 1, mid + 1, end, l, r, val); return ans; } void sol() { _rep(i, 1, n) a[i] = read(); build(1, 1, n); _for(i, m) { int op = read(); if(op == 1) { int x = read(), val = read(); a[x] = val; update(1, 1, n, x, val); } else { int x = read(); LL cl = x - 1, cr = n - x; if(x > 1) cl = x - 1 - queryl(1, 1, n, 1, x - 1, a[x]); if(x < n) cr = queryr(1, 1, n, x + 1, n, a[x]) - x - 1; LL ans = cl + cr + cl * cr + 1; printf("%lld\n", ans); } } } int main() { n = read(), m = read(); sol(); return 0; }
#include <bits/stdc++.h> #define _for(i, a) for(int i = 0, lennn = (a); i < lennn; ++i) #define _rep(i, a, b) for(int i = (a), lennn = (b); i <= lennn; ++i) using namespace std; typedef long long LL; const int maxn = 100005; inline LL read() { LL x(0), f(1); char ch(getchar()); while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int n, m; LL a[maxn]; LL T[maxn << 2]; void build(int node, int beg, int end) { if (beg == end) { T[node] = a[beg]; return; } int mid = (beg + end) >> 1; build(node << 1, beg, mid); build(node << 1 | 1, mid + 1, end); T[node] = min(T[node << 1], T[node << 1 | 1]); } void update(int node, int beg, int end, int pos, LL val) { if(beg == end) { T[node] = val; return; } int mid = (beg + end) >> 1; if(pos <= mid) update(node << 1, beg, mid, pos, val); else update(node << 1 | 1, mid + 1, end, pos, val); T[node] = min(T[node << 1], T[node << 1 | 1]); } int query(int node, int beg, int end, int l, int r) { if (l <= beg && r >= end) return T[node]; int ans = 0x3f3f3f3f; int mid = (beg + end) >> 1; if(mid >= l) ans = min(ans, query(node << 1, beg, mid, l, r)); if(mid < r) ans = min(ans, query(node << 1 | 1, mid + 1, end, l, r)); return ans; } void sol() { _rep(i, 1, n) a[i] = read(); build(1, 1, n); _for(i, m) { int op = read(); if(op == 1) { int x = read(), val = read(); a[x] = val; update(1, 1, n, x, val); } else { int x = read(); LL cl = 0, cr = 0; if(x > 1) { LL l = 1, r = x - 1; while(l <= r) { LL mid = (l + r) >> 1; if(query(1, 1, n, mid, x - 1) > a[x]) { cl = x - mid; r = mid - 1; } else l = mid + 1; } } if(x < n) { LL l = x + 1, r = n; while(l <= r) { LL mid = (l + r) >> 1; if(query(1, 1, n, x + 1, mid) > a[x]) { cr = mid - x; l = mid + 1; } else r = mid - 1; } } LL ans = cl + cr + cl * cr + 1; printf("%lld\n", ans); } } } int main() { // freopen("in.txt", "r", stdin); n = read(), m = read(); sol(); return 0; }
judge:牛客
给你一个 \(n\times n\) 的矩阵,其数字的排布方式以下:
0 1 3 6 10 2 4 7 11 15 5 8 12 16 19 9 13 17 20 22 14 18 21 23 24
求出第 \(x\) 行第 \(y\) 列的元素的值. 注意\((0≤x≤1000000000, 0≤y≤1000000000, 1≤n≤1000000001)\).
旋转一下矩阵:
0 2 1 5 4 3 9 8 7 6 14 13 12 11 10 18 17 16 15 21 20 19 23 22 24
那么第 \(x\) 行第 \(y\) 列就对应第 \(x+y-1\) 行. 假设 \(r=x+y-1\).
#include <bits/stdc++.h> using namespace std; typedef long long LL; inline int read() { int x(0), f(1); char ch(getchar()); while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int main() { LL n = read(), x = read() + 1, y = read() + 1, ans = 0; if(x + y <= n + 1) { ans = (x + y - 1) * (x + y - 2) / 2 + x - 1; } else { LL _x = n - x + 1, _y = n - y + 1; ans = (_x + _y - 1) * (_x + _y - 2) / 2 + _x; ans = n * n - ans; } printf("%lld\n", ans); return 0; }
judge:牛客
有 n 座城市,m 条双向道路,一条道路要走一天,每条道路的费用是 n ^ m ( n 是所携带的物品数量, m 是第几天),给你一个出发城市 S ,目的地城市 T ,预算 B ,问最多能携带多少物品。
先用floyed求出任意两个城市之间的最短距离。而后二分答案,check一下就好了。
// #pragma GCC optimize(2) #include <bits/stdc++.h> #define m_p make_pair #define p_i pair<int, int> #define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i) #define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n" #define mem(a, b) memset(a, b, sizeof(a)) #define mem0(a) memset(a, 0, sizeof(a)) #define fil(a, b) fill(a.begin(), a.end(), b); #define scl(x) scanf("%lld", &x) #define sc(x) scanf("%d", &x) #define pf(x) printf("%d\n", x) #define pfl(x) printf("%lld\n", x) #define abs(x) ((x) > 0 ? (x) : -(x)) #define PI acos(-1) #define lowbit(x) (x & (-x)) #define dg if(debug) #define nl(i, n) (i == n - 1 ? "\n":" ") #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) using namespace std; typedef long long LL; // typedef __int128 LL; typedef unsigned long long ULL; const int maxn = 100005; const int maxm = 1000005; const int maxp = 30; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1000000007; const double eps = 1e-8; const double e = 2.718281828; int debug = 0; LL dis[110][110]; LL b; inline int read() { int x(0), f(1); char ch(getchar()); while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } struct poi { }; LL check(LL x,LL y){ LL sum=0; LL flag=1; for(int i=1;i<=y;i++){ flag*=x; sum+=flag; if(sum>b) return sum; } return sum; } void init() { for(int i=0;i<109;i++) for(int j=0;j<109;j++) dis[i][j]=110; ios::sync_with_stdio(0); } void sol() { init(); LL n,m; cin>>n>>m; for(LL i=1;i<=m;i++){ LL x,y; cin>>x>>y; dis[x][y]=dis[y][x]=1; } for(LL k=1;k<=n;k++) for(LL i=1;i<=n;i++) for(LL j=1;j<=n;j++) if(dis[i][j] > dis[i][k] + dis[k][j]) dis[i][j] = dis[i][k] + dis[k][j]; LL q; cin>>q; while(q--){ LL s,t; cin>>s>>t>>b; LL l=0,r=1e9+10; LL ans=0; LL mid; while(l<r){ mid=(l+r)/2; LL flag=check(mid,dis[s][t]); if(flag>=b){ r=mid; }else{ l=mid+1; } if(flag<=b){ ans=max(ans,mid); } } cout<<ans<<endl; } } int main() { //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifndef ONLINE_JUDGE //freopen("in.txt", "r", stdin); debug = 1; #endif time_t beg, end; if(debug) beg = clock(); sol(); return 0; }
judge:牛客
把n个皇后安排在一个 \(n\times n\) 的矩阵里,以便每行每列都有且仅有一个皇后,其中矩阵的某些位置不可用。
计算合法的方案数。
状压dp。
给 \(n\) 个皇后编号为 \(1,2,...,n\)。
假设 \(1\) 号皇后在第一行,\(2\) 号皇后在第 \(2\) 行,以此类推,\(n\) 号皇后在第 \(n\) 行。
保存每一列的皇后状态。假设 \(n\) 为 \(2\),第 \(2\) 列已经被安排了皇后,那么状态就为0 1
。因为 \(n\) 只有 \(20\),因此能够用一个 \(int\) 类型的整数保存每一列的状态,二进制位为 \(1\) 就表明这一列已经被安排了皇后。以后就能够考虑状态转移了。
假设 \(n\) 为 \(4\)。依次枚举 \(1-n\) 号皇后,当 \(1\) 号皇后安排在第 \(1\) 列时,\(2\) 号皇后就能够被安排在第 \(2,3,4\) 列,那么1000
就能够转移到1100
,1010
,1001
。固然,这时是默认全部位置均可用,假设第 \(2\) 行第 \(3\) 列的位置不可用,那么1000
就只能转移到1100
,1001
。
设置0001
,0010
,0100
,1000
的方案数为 \(1\),求出全部的转移以后,1111
表明的方案数就是基于“假设 \(1\) 号皇后在第一行,\(2\) 号皇后在第2行,以此类推,\(n\) 号皇后在第 \(n\) 行”的所有方案数。
答案乘以\(A_n^n\)就是最终的的方案数。
#include <bits/stdc++.h> #define _for(i, a) for(int i = 0, lennn = (a); i < lennn; ++i) #define _rep(i, a, b) for(int i = (a), lennn = (b); i <= lennn; ++i) using namespace std; typedef long long LL; const int maxn = 25; const int mod = 1000000007; inline int read() { int x(0), f(1); char ch(getchar()); while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int n; int a[maxn][maxn]; LL dp[1 << 21]; LL ji[maxn]; void init() { _for(i, (1 << n)) dp[i] = 0; } int getN1(int i) { int num = 0; while(i) num += (i & 1), i >>= 1; return num; } void sol() { init(); _for(i, n) _for(j, n) a[i][j] = read(); _for(i, n) if(!a[0][i]) dp[1 << i] = 1; for(int i = 1; i < (1 << n); ++i) { int cnt = getN1(i); _for(j, n) { if(i & (1 << j)) continue; if(a[cnt][j]) continue; dp[i | (1 << j)] += dp[i]; dp[i | (1 << j)] %= mod; } } printf("%lld\n", dp[(1 << n) - 1] * ji[n] % mod); } int main() { ji[1] = 1; for(int i = 2; i <= 21; ++i) ji[i] = ji[i - 1] * i % mod; n = read(); sol(); return 0; }
judge:牛客
签到题
每一个园子有个园子号,每一个动物有个动物号,合起来就是动物编号.
给出园子号和动物号,求出动物编号.
无
#include <bits/stdc++.h> using namespace std; int main() { string a, b; cin >> a >> b; cout << a << b; }