单挑养成计划【2】 AtCoder Grand Contest 005
ABC
我懒得写了。。(啪
D - ~K Perm Counting
题意:求有多少种1~N的全排列,不存在位置i,使得i上的数ai满足 |ai - i| = K。
题解:一眼容斥。思考怎么算有i个不合法位置的方案数Mi。考虑转化成一个二分图,左边N个数代表位置,右边N个数代表数字。在图上建边跑DP。有很多种姿势的DP啊非常迷……边边点点的搞一搞(
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <vector> 6 #include <algorithm> 7 using namespace std; 8 typedef long long ll; 9 #define rp(i,a,b) for(int (i)=(int)(a);i<(int)(b);++i) 10 ll dp[4020][2020][2]; 11 ll mod=924844033; 12 int main(){ 13 int N,K; 14 cin>>N>>K; 15 vector<ll> m; 16 ll c=0,s=0; 17 bool t[2001]; 18 for(int i=1;i<N+1;i++){ 19 if(!t[i]){ 20 s+=(N-i)/K*2; 21 rp(j,0,(N-i)/K) m.push_back(c); 22 c++; 23 rp(j,0,(N-i)/K) m.push_back(c); 24 c++; 25 for(int j=i;j<=N;j+=K){ 26 t[j]=true; 27 } 28 } 29 } 30 dp[0][0][0]=1; 31 rp(i,0,s){ 32 rp(j,0,min(ll(2001),ll(i+1))){ 33 (dp[i+1][j+1][1]+=dp[i][j][0])%=mod; 34 if(m[i]!=m[i-1]) (dp[i+1][j+1][1]+=dp[i][j][1])%=mod; 35 (dp[i+1][j][0]+=(dp[i][j][0]+dp[i][j][1]))%=mod; 36 } 37 } 38 ll per[2001]; 39 per[0]=1; 40 rp(i,1,2001){ 41 per[i]=(per[i-1]*i)%mod; 42 } 43 ll sub=0; 44 for(int i=1; i<=min(ll(s),ll(N)); ++i) 45 { 46 if(i%2==0) sub = (sub - ((dp[s][i][0]+dp[s][i][1])*per[N-i])%mod + mod)%mod; 47 else sub = (sub + ((dp[s][i][0]+dp[s][i][1])*per[N-i])%mod)%mod; 48 } 49 50 ll ans=(per[N]-sub+mod)%mod; 51 cout << ans << endl; 52 return 0; 53 54 };
E - Sugigma: The Showdown
题意:两个人在一张图上做游戏,A有一个红色的生成树,B有一个蓝色的生成树,起点分别在X,Y号点,两个人轮流走,每次只能沿自己对应的颜色走一条边或者不动弹。问A最多能拖多少步才能让B追上。
题解:我们很容易发现,A是足够安全的当且仅当有两个点u,v满足 Lred(u,v) = 1 且 Lblue(u,v) >= 3,并且A站在u,v之中的一点上。那么问题就转化成了A能不能安全的跑到这些安全点上。因为两棵树放在一起不好处理,我们选择固定B的那一棵不动,A的行为就可以表示为在蓝色的树上跳来跳去。并且由于A当前不在安全点上,所以跳一步的距离不会超过2:这样A就只能始终在以B当前点为根的子树上,不会跳回去自寻死路。到这里问题就简单啦,因为很容易知道当前点的深度(B追到这里的步数),A无法占据安全点的话,坚持到尽可能深的点上被抓就好啦。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <algorithm> 5 #include <iostream> 6 #include <vector> 7 #include <queue> 8 using namespace std; 9 const int maxn = 2e6 + 5; 10 vector<int> blue[maxn], red[maxn]; 11 int dep[maxn], fa[maxn], dp[maxn]; 12 bool safe[maxn], vis[maxn]; 13 void dfs(int v, int p) { 14 fa[v] = p; 15 for (int i=0; i<blue[v].size(); i++) if(blue[v][i] != p) { 16 dep[blue[v][i]] = dep[v] + 1; 17 dfs(blue[v][i], v); 18 } 19 } 20 bool atMost2(int x, int y) { 21 return (fa[x] == fa[y]) || (fa[x] == y) || (x == fa[y]) || (fa[fa[x]] == y) || (x == fa[fa[y]]); 22 } 23 int main() { 24 int n, X, Y, x, y; 25 scanf("%d %d %d", &n, &X, &Y); 26 for (int i=1; i<n; i++) { 27 scanf("%d %d", &x, &y); 28 red[x].push_back(y), red[y].push_back(x); 29 } 30 for (int i=1; i<n; i++) { 31 scanf("%d %d", &x, &y); 32 blue[x].push_back(y), blue[y].push_back(x); 33 } 34 dfs(Y, -1); 35 for (int i=1; i<=n; i++) 36 for (int j=0; j<red[i].size(); j++) 37 if (!atMost2(i, red[i][j])) 38 safe[i] = safe[red[i][j]] = 1; 39 if (safe[X]) {puts("-1"); return 0;} 40 memset(dp, -1, sizeof(dp)); 41 queue<int> q; 42 q.push(X); dp[X] = 0; vis[X] = 0; 43 int ans = 0; 44 while (!q.empty()) { 45 int u = q.front(); q.pop(); 46 if (dp[u] >= dep[u]) continue; 47 if (safe[u]) {puts("-1"); return 0;} 48 ans = max(ans, dep[u] * 2); 49 for (int i=0; i<red[u].size(); i++) { 50 int v = red[u][i]; 51 if (!vis[v] && dp[u] + 1 < dep[v] && atMost2(u, v)) { 52 dp[v] = dp[u] + 1; 53 vis[v] = 1; 54 q.push(v); 55 } 56 } 57 } 58 printf("%d\n", ans); 59 return 0; 60 }
F。。等我学会了FFT再说吧(