日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P3301 [SDOI2013]方程

發布時間:2023/12/3 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P3301 [SDOI2013]方程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

P3301 [SDOI2013]方程

題意:

題解:

插板法介紹

首先要先講組合數學的一個方法:插板法

問題引出:把10個球放進三個盒子,每個箱子至少一個有多少種分法?

10個球就有9個空隙,我們可以考慮在這個9個空隙中放入兩個隔板,這樣10個球就被分成了3組,就相當于放入了三個箱子。
答案就是C10?13?1C_{10-1}^{3-1}C10?13?1?
也就是n個球放入m個盒子,每個箱子至少一個有Cn?1m?1C_{n-1}^{m-1}Cn?1m?1?種分法

問題2:把10個球放進三個盒子有多少種分法

此時箱子內可以沒有球,我們可以預先在3個盒子里都放一個球,則問題轉化為將13個球放進3個盒子里,每個盒子至少一個有多少中放法。答案為C122C_{12}^2C122?
也就是n個球放入m個盒子,有Cn+m?1m?1C_{n+m-1}^{m-1}Cn+m?1m?1?種分法

本題講解:

如果沒有限制,就是求x1+x2+..+xn=Mx_{1}+x_{2}+..+x_{n}=Mx1?+x2?+..+xn?=M,這不就相當于把M分配到n個箱子里,且每個箱子不能為空,這樣答案就是CM?1n?1C_{M-1}^{n-1}CM?1n?1?
但是題目有兩類限制:

第二類限制為:Xi>=AiX_{i}>=A_{i}Xi?>=Ai?,我們可以巧妙的轉化,對于第i個箱子要求分配數要大于AiA_{i}Ai?,那我們可以認為先將Ai?1A_{i}-1Ai??1分配給XiX_{i}Xi?,然后剩下還是老分法(分配給n個箱子,每個箱子至少一個)。這種方法M要減去Ai?1A_{i}-1Ai??1(相當于提前分配了)

對于第一類限制,Xi<=AiX_{i}<=A_{i}Xi?<=Ai?,就比較麻煩了,不過題目中限制數最大為8,我們可以用容斥解決
先計算不考慮前n1個數的限制方案數-前n1個數至少有一個不滿足條件的方案數+前n1個數至少有2個不滿足條件的方案數-…
代碼具體就是枚舉狀態S,其二進制狀態下,第i位為1表示計算了第i個數,如果有奇數個1就是減,偶數個1就是加
因為n,m很大,且p不一定為質數,所以用擴展盧卡斯
容斥代碼:

for (int s= 0; s <= (1 << n1) - 1; s++) {int num= 0;ll now= m;for (int i= 1; i <= n1; i++) {if ((1 << (i - 1)) & s) {now-= a[i];num++;}}ll tmp= exLucas(now - 1, n - 1, mod);// printf("tmp=%lld\n",tmp);ans= (ans + ((num & 1) ? (mod - tmp) % mod : tmp)) % mod;}

這樣做70分,會被卡常
題目所給的模數只有三種:
262203414=2?3?11?397?1007262203414=2*3*11*397*1007262203414=2?3?11?397?1007
437367875=53?73?1012437367875=5^3*7^3*101^2437367875=53?73?1012
10007是質數10007是質數10007
這樣可以省去擴展盧卡斯分析qk的過程,大大減少常數
同時優化一下擴展盧卡斯處理階乘的過程,提前計算好,這樣也可以大力卡常。不然根本卡不過去。

代碼:

// Problem: P3301 [SDOI2013]方程 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P3301 // Memory Limit: 125 MB // Time Limit: 1000 ms // Data:2021-08-27 16:25:48 // By Jozky#include <bits/stdc++.h> #include <unordered_map> #define debug(a, b) printf("%s = %d\n", a, b); using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> PII; clock_t startTime, endTime; //Fe~Jozky const ll INF_ll= 1e18; const int INF_int= 0x3f3f3f3f; void read(){}; template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar) {x= 0;char c= getchar();bool flag= 0;while (c < '0' || c > '9')flag|= (c == '-'), c= getchar();while (c >= '0' && c <= '9')x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();if (flag)x= -x;read(Ar...); } template <typename T> inline void write(T x) {if (x < 0) {x= ~(x - 1);putchar('-');}if (x > 9)write(x / 10);putchar(x % 10 + '0'); } void rd_test() { #ifdef LOCALstartTime= clock();freopen("in.txt", "r", stdin); #endif } void Time_test() { #ifdef LOCALendTime= clock();printf("\nRun Time:%lfs\n", (double)(endTime - startTime) / CLOCKS_PER_SEC); #endif } ll mod;void exgcd(ll a, ll b, ll& x, ll& y) {if (!b) {x= 1, y= 0;return;}exgcd(b, a % b, y, x);y-= a / b * x;return; }inline ll inv(ll n, ll p) {ll x, y;exgcd(n, p, x, y);return (x + p) % p; }ll qpow(ll base, ll p, ll mod) {ll ret= 1;for (; p; p>>= 1, base= base * base % mod)if (p & 1)ret= ret * base % mod;return ret; }ll CRT(int n, ll* a, ll* m) {ll M= 1, ret= 0;for (ll i= 1; i <= n; i++)M*= m[i];for (ll i= 1; i <= n; i++) {ll w= M / m[i];ret= (ret + a[i] * w % mod * inv(w, m[i]) % mod) % mod;}return (ret + mod) % mod; } int retfac[10]; ll calc(ll n, ll q, ll qk,ll retfac) {if (!n)return 1;ll ret= retfac;ret= qpow(ret, n / qk, qk);for (ll i= n / qk * qk + 1; i <= n; i++)if (i % q)ret= ret * (i % qk) % qk;return ret * calc(n / q, q, qk,retfac) % qk; }ll multiLucas(ll n, ll m, ll q, ll qk,ll retfac) {int cnt= 0;for (ll i= n; i; i/= q)cnt+= i / q;for (ll i= m; i; i/= q)cnt-= i / q;for (ll i= n - m; i; i/= q)cnt-= i / q;return qpow(q, cnt, qk) * calc(n, q, qk,retfac) % qk * inv(calc(m, q, qk,retfac), qk) % qk * inv(calc(n - m, q, qk,retfac), qk) % qk; }int cnt; ll qk[20]; ll qw[20]; ll exLucas(ll n, ll m, ll p) {if(m>n)return 0;ll a[20]; // int cnt= 0; // ll qk[20], a[20]; //存放所有的 q^k 和待合并答案的結果 // // for (ll i= 2; i * i <= p; ++i) //質因數分解 // { // if (p % i == 0) { // qk[++cnt]= 1; // while (p % i == 0) // qk[cnt]*= i, p/= i; // a[cnt]= multiLucas(n, m, i, qk[cnt]); // } // } // if (p > 1) // qk[++cnt]= p, a[cnt]= multiLucas(n, m, p, p);for(int i=1;i<=cnt;i++){a[i]=multiLucas(n, m,qw[i] , qk[i],retfac[i]);}return CRT(cnt, a, qk); //CRT 合并答案 } void init(ll p) {for (ll i= 2; i * i <= p; ++i) //質因數分解{if (p % i == 0) {qk[++cnt]= 1;qw[cnt]=i;while (p % i == 0)qk[cnt]*= i, p/= i;}}if (p > 1)qk[++cnt]= p,qw[cnt]=p;for(int i=1;i<=cnt;i++){retfac[i]=1;for(int j=1;j<=qk[i];j++){if(j%qw[i]){retfac[i] = 1ll * retfac[i] * j % qk[i];}}} }ll t; const int maxn= 10; int a[maxn], b[maxn]; ll n, n1, n2, m; void init(){} int main() {//rd_test();read(t, mod);init(mod);//預處理,不然會t三個點 while (t--) {read(n, n1, n2, m);for (int i= 1; i <= n1; i++)read(a[i]);for (int i= 1; i <= n2; i++) {read(b[i]);m-= (b[i] - 1);}//ll sum=exLucas(m-1,n-1,mod);ll ans= 0;for (int s= 0; s <= (1 << n1) - 1; s++) {int num= 0;ll now= m;for (int i= 1; i <= n1; i++) {if ((1 << (i - 1)) & s) {now-= a[i];num++;}}ll tmp= exLucas(now - 1, n - 1, mod);// printf("tmp=%lld\n",tmp);ans= (ans + ((num & 1) ? (mod - tmp) % mod : tmp)) % mod;}printf("%lld\n", ans);}return 0;//Time_test(); }

總結

以上是生活随笔為你收集整理的P3301 [SDOI2013]方程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。