noip模拟测试15


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 }
t1 Code


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 }
t2 Code


T3:石头剪刀布(rps)

  懵比……

猜你喜欢

转载自www.cnblogs.com/Gkeng/p/11326961.html