A 求组合数
首先咱一开始并没有看到 Q 的数据范围,并且子任务表格里还有一堆 none (???)
于是整个机房都打算阿了出题人
后来滚回来看的时候 bug 基本都修好了,于是开始挠头发(这个数据范围真是要人命啊 Q 居然可以到 2e9 ...)
但后来看到了这个 m 的范围比较小,于是估计这道题就是利用 m 比较小的性质来做的
于是列一下 \(C_n^m\) 的公式:
\[ C_n^m ={n!\over m!·(n-m)!} \] 并没有什么软用...然后用下降幂表示一下:\[ C_n^m ={n^{\underline{m}}\over m!} \] 说人话就是:\[ C_n^m ={n*(n-1)*···*(n-m+1)\over m*(m-1)*···*1} \] 发现上下都只有 \(m\) 项(挠头)于是想想如果 mod 为质数怎么做: 咱可以 \(O(m)\) 得去得到这个公式上面和下面两个部分的值,然后 \(O(log ~mod)\) 蒙哥马利一下就可以得到答案了 【汗
然后咱考虑 mod 不是质数的情况,这个时候咱需要对上下两部分的 m 个数进行质因子分解,这是 \(\sqrt n\) 的复杂度,但咱可以用人类智慧优化到 \(\sqrt n\over log ~n\) ,具体康代码(好吧不就是普通的欧拉筛么)...
然后咱把上下两部分的质因子分别加起来,上面的每个质因子 \(p_i\) 的次数 \(k_{i1}\) 减去下面质因子的次数 \(k_{i2}\) ,然后每个质因子快速幂一下就好了(这个复杂度好像是 $\sqrt n ~loglog ~n $ 级别的 )
但是咱发现太大的质因子存不下呢...那咱就把这些太大的质因子(超过 \(\sqrt n\) 的)用 map 去存就好了(复杂度大概是 \(m ~log ~m\) ...?最后遍历时候的复杂度也不高(应该...)
然后咱本地测了最大数据... T 飞上天(顿时懵逼
懵逼一会儿之后开始补救,大概就是对于 mod 是质数的情况进行了特判...少了 \(\sqrt n\over log ~n\) 的复杂度...
最后就是一边自闭一边把代码交上去准备 T 飞了...
【结果最后数据特别友好,真是气人啊,浪费感情...
// by Judge#pragma GCC optimize("Ofast")#include#define Rg register#define fp(i, a, b) for (Rg int i = (a), I = (b) + 1; i < I; ++i)#define fd(i, a, b) for (Rg int i = (a), I = (b)-1; i > I; --i)#define ll long longusing namespace std;const int M = 5e4 + 3;typedef int arr[M];#ifndef Judge#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)#endifchar buf[1 << 21], *p1 = buf, *p2 = buf;inline bool cmax(int& a, int b) { return a < b ? a = b, 1 : 0; }inline bool cmin(int& a, int b) { return a > b ? a = b, 1 : 0; }inline int read() { int x = 0, f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -1; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; return x * f;}int n, m, mod, id1[M];map id2;inline int mul(int x, int y) { return 1ll * x * y % mod; }inline int qpow(int x, int p) { Rg int s = 1; for (; p; p >>= 1, x = mul(x, x)) if (p & 1) s = mul(s, x); return s;}int cnt, p[M], v[M];inline void prep(int n) { fp(i, 2, n) { if (!v[i]) p[++cnt] = i, v[p[cnt]] = cnt; for (Rg int j = 1; j <= cnt && i * p[j] <= n; ++j) { v[i * p[j]] = 1; if (!(i % p[j])) break; } }}inline void add(int x, int V) { fp(i, 1, cnt) { if (p[i] * p[i] > x) break; while (!(x % p[i])) id1[i] += V, x /= p[i]; } if (x > 1) { if (x > p[cnt]) id2[x] += V; else id1[v[x]] += V; }}#define IT map ::iteratorinline int solv() { Rg int ans = 1; fp(i, 1, cnt) if (id1[i]) ans = mul(ans, qpow(p[i], id1[i])); for (IT it = id2.begin(); it != id2.end(); ++it) ans = mul(ans, qpow(it->first, it->second)); return ans;}inline bool isprime(int x) { fp(i, 1, cnt) { if (p[i] * p[i] > x) return 1; if (!(x % p[i])) return 0; } return 1;}inline void solv0() { Rg int p = 1, q = 1; fp(i, 1, m) p = mul(p, n - i + 1), q = mul(q, i); printf("%d\n", mul(p, qpow(q, mod - 2)));}int main() { int T = read(); prep(5e4); while (T--) { n = read(), m = read(), mod = read(); if (isprime(mod)) { solv0(); continue; } memset(id1, 0, sizeof id1), id2.clear(); fp(i, 1, m) add(n - i + 1, 1), add(i, -1); printf("%d\n", solv()); } return 0;}
B 铺地板
比赛的时候咱可是放过话的:“网络流这种东西 CSP 怎么可能会考,你见过 NOIP 考过 wll 么?他要敢考咱就敢爆零!” 于是咱并没有黑白染色冷静一下并且华丽爆炸...
给个乱打的代码(没有交过 因为交不了)
评价:有一定参考价值,若出锅请轻喷...
//by Judge#include#define Rg register#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i I;--i)#define go(u) for(Rg int i=head[u],v=e[i].to;i;v=e[i=e[i].nxt].to)#define ll long longusing namespace std;const int M=65;typedef int arr[M][M];typedef int ARR[M*M];const int h[5]={0,-1,1,0,0},l[5]={0,0,0,-1,1};#ifndef Judge#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)#endifchar buf[1<<21],*p1=buf,*p2=buf;inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;} inline int cread(){ char c=getchar(); while(c!='.'&&c!='#') c=getchar(); return c=='.';} int n,cnt,tim,pat,ans; ARR head,used,Get; arr a,id;struct Edge{ int to,nxt; }e[M*M<<2];inline void add(int u,int v){ cerr< <<" "< <<"\n"; e[++pat]=(Edge){v,head[u]},head[u]=pat;}inline int calc(int x,int y){ return a[x-1][y]+a[x][y-1]+a[x+1][y]+a[x][y+1];}bool find(int u){ cerr< <<"!!!\n"; go(u) if(used[v]
C 军训队列
一开始以为是斜优 dp 想着这出题人也是够毒瘤(虽说也不算太超纲...吧?),结果一看数据范围 500 , \(n^3\) 喜 dp (斜优 × 暴力 √ )
// by Judge#pragma GCC optimize("Ofast")#include#define Rg register#define fp(i, a, b) for (Rg int i = (a), I = (b) + 1; i < I; ++i)#define fd(i, a, b) for (Rg int i = (a), I = (b)-1; i > I; --i)#define ll long longusing namespace std;const int M = 503;typedef int arr[M];#ifndef Judge#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)#endifchar buf[1 << 21], *p1 = buf, *p2 = buf;inline int read() { int x = 0, f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -1; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; return x * f;}int n, K, a[M], f[M][M];inline int Min(int x, int y) { return x < y ? x : y; }int main() { n = read(), K = read(); if (K >= n) return !printf("0\n"); fp(i, 1, n) a[i] = read(); sort(a + 1, a + 1 + n), memset(f, 0x3f, sizeof f), f[0][0] = 0; fp(i, 1, n) fp(j, 1, Min(i, K)) fp(k, 0, i - 1) f[i][j] = Min(f[i][j], f[k][j - 1] + (a[i] - a[k + 1]) * (a[i] - a[k + 1])); return !printf("%d\n", f[n][K]);}