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; }