T1:建设城市(city)
第一眼看是组合,然后看到k的限制发现是容斥
用插板法加容斥得出:$\sum_{i=0}^{m-i*k-1 \leq n-1}C_n^i*C_{m-i*k-1}^{n-1}*(-1)^i$
但发现$n$的范围是$10^9$,组合数计算是$O(n)$的
但又发现$m$的范围是$10^7$,所以特判$n>m$的情况就行了
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<vector> 7 #include<queue> 8 #define ll long long 9 using namespace std; 10 const int MAXN=10000005; 11 const ll D=998244353; 12 ll n,m,k,ans,fac[MAXN],inv[MAXN]; 13 ll qpow(ll x,ll k) { 14 ll ret=1; 15 while(k) { 16 if(k&1) ret=ret*x%D; 17 x=x*x%D; 18 k>>=1; 19 } 20 return ret; 21 } 22 void first() { 23 fac[0]=inv[0]=1; 24 for(int i=1;i<=m;i++) 25 fac[i]=fac[i-1]*i%D; 26 inv[m]=qpow(fac[m],D-2); 27 for(int i=m-1;i>=1;i--) 28 inv[i]=inv[i+1]*(i+1)%D; 29 } 30 ll C(int x,int y) { 31 return fac[x]*inv[x-y]%D*inv[y]%D; 32 } 33 int main() { 34 scanf("%lld%lld%lld",&n,&m,&k); 35 if(n>m||m>n*k) { 36 printf("0\n"); 37 return 0; 38 } else if(n==m||m==n*k) { 39 printf("1\n"); 40 return 0; 41 } 42 first(); 43 ans=C(m-1,n-1); 44 for(ll i=1;;i++) { 45 if(m-i*k-1<n-1) break; 46 if(i&1) ans=(ans-C(n,i)*C(m-i*k-1,n-1))%D; 47 else ans=(ans+C(n,i)*C(m-i*k-1,n-1))%D; 48 } 49 printf("%lld\n",(ans%D+D)%D); 50 return 0; 51 }
T2: 轰炸行动(bomb)
读题出锅……
就是简单的tarjan,缩完scc后跑个拓扑求点权的最长链就行了
自己手玩几组数据就知道了
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<vector> 7 #include<queue> 8 #include<bitset> 9 #define ll long long 10 using namespace std; 11 const int MAXN=1100000,INF=0x3f3f3f3f; 12 int n,m,ans,dfn[MAXN],low[MAXN],stk[MAXN],tp,num; 13 int scc_cnt,scc[MAXN],siz[MAXN],du[MAXN],f[MAXN]; 14 bool vis[MAXN]; 15 struct edge { 16 int x,y; 17 }e[MAXN]; 18 struct node { 19 int to,nxt; 20 }mp[MAXN]; 21 int h[MAXN],tot; 22 void add(int x,int y) { 23 mp[++tot].to=y; 24 mp[tot].nxt=h[x]; 25 h[x]=tot; 26 } 27 void tarjan(int u) { 28 dfn[u]=low[u]=++num; 29 stk[++tp]=u;vis[u]=1; 30 for(int i=h[u];i;i=mp[i].nxt) { 31 int v=mp[i].to; 32 if(!dfn[v]) { 33 tarjan(v); 34 low[u]=min(low[u],low[v]); 35 } else if(vis[v]) low[u]=min(low[u],dfn[v]); 36 } 37 if(dfn[u]==low[u]) { 38 ++scc_cnt; 39 int tmp; 40 do { 41 tmp=stk[tp--]; 42 vis[tmp]=0; 43 siz[scc_cnt]++; 44 scc[tmp]=scc_cnt; 45 }while(tmp!=u); 46 } 47 } 48 void build() { 49 memset(h,0,sizeof(h));tot=0; 50 for(int i=1;i<=m;i++) 51 if(scc[e[i].x]!=scc[e[i].y]) { 52 add(scc[e[i].x],scc[e[i].y]); 53 du[scc[e[i].y]]++; 54 } 55 } 56 void topo() { 57 queue<int> q; 58 for(int i=1;i<=scc_cnt;i++) 59 if(!du[i]) q.push(i); 60 while(!q.empty()) { 61 int u=q.front(); q.pop(); 62 f[u]+=siz[u]; 63 for(int i=h[u];i;i=mp[i].nxt) { 64 int v=mp[i].to; 65 f[v]=max(f[v],f[u]); 66 if(!--du[v]) q.push(v); 67 } 68 } 69 } 70 int main() { 71 scanf("%d%d",&n,&m); 72 for(int i=1;i<=m;i++) { 73 scanf("%d%d",&e[i].x,&e[i].y); 74 add(e[i].x,e[i].y); 75 } 76 for(int i=1;i<=n;i++) 77 if(!dfn[i]) tarjan(i); 78 build(); 79 topo(); 80 for(int i=1;i<=scc_cnt;i++) ans=max(ans,f[i]); 81 printf("%d\n",ans); 82 return 0; 83 }
T3:石头剪刀布(rps)
懵比……