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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Wannafly 挑战赛27 题解

發布時間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Wannafly 挑战赛27 题解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Wannafly 挑戰賽27

題目連接

https://www.nowcoder.com/acm/contest/215#question


A.灰魔法師

題目

題解

考慮到可能的完全平方數只有400400400多個,因此對于每種數,直接暴力枚舉所有的完全平方數計算一下就可以了.

代碼

#include <iostream> #define int long long const int N = 100007; int a[N]; int n; int p2[N]; int tot; signed main() {for(int i = 1;;i++) {int a = i*i;if(a > 2*N) break;p2[tot++] = a;}std::cin >> n;for(int i = 1;i <= n;++i) {int tmp;std::cin >> tmp;a[tmp] ++;}int ans = 0;for(int i = 1;i <= 100000;++i) {if(a[i] == 0) continue;for(int j = 0;j < tot;++j) {int an = p2[j] - i;if(an < i) continue;if(an == i) ans += a[i]*(a[i]-1)/2;else if(an <= 100000)ans += a[i]*a[an];}}std::cout << ans << std::endl; }

B.紫魔法師

題目

題解

注意到至少當存在一個奇環的情況下,一定需要333種顏色,而其他情況下只要222種顏色就足夠了.

只需要用tarjan算法求其點雙連通分量的大小即可.

代碼

#include <iostream> #include <algorithm> #include <cstring> #include <stack> #include <vector> #define pr(x) std::cout << #x << ':' << x << std::endl #define rep(i,a,b) for(int i = a;i <= b;++i) const int N = 100007; struct edge{int u,v,nxt; }es[N<<2]; int head[N],cnt; int vis[N],dfn[N],low[N],idx; int v[N<<1],u[N<<1]; std::stack<int> stk; void addedge(int u,int v) {es[cnt].u = u;es[cnt].v = v;es[cnt].nxt = head[u];head[u] = cnt++; } int flag; void tarjan(int u,int fa) {dfn[u] = low[u] = ++idx;vis[u] = 1;for(int e = head[u];e != -1;e = es[e].nxt) {int v = es[e].v;if(v == fa) continue;stk.push(e);if(!vis[v]) {tarjan(v,u);if(low[u] > low[v]) low[u] = low[v];if(dfn[u] <= low[v]) {//割點int cnt = 0;while(true) {int se = stk.top();stk.pop();cnt++;if(se == e) break;}if(cnt > 1 && cnt % 2 != 0) {flag = 1;}}}else low[u] = std::min(low[u],dfn[v]);} } int n,m; int main() {memset(head,-1,sizeof(head));std::ios::sync_with_stdio(false);std::cin >> n >> m;rep(i,1,m) {int u,v;std::cin >> u >> v;addedge(u,v);addedge(v,u);}tarjan(1,0);if(flag) std::cout << "3" << std::endl;else std::cout << "2" << std::endl;return 0; }

C.藍膜法師

題目

題解

樹形dp

狀態定義

定義dp[u][i]dp[u][i]dp[u][i]表示uuu子樹中包含節點uuu的連通塊大小為iii,且其余聯通塊大小均≤k\le kk的方案數.

注意上述定義中dp[u][0]dp[u][0]dp[u][0]是沒有意義的,我們再定義dp[u][0]=∑t=1min{size[u],k}dp[u][t]dp[u][0] = \sum_{t = 1}^{min\{size[u],k\}} dp[u][t]dp[u][0]=t=1min{size[u],k}?dp[u][t].

轉移方程的計算:

當我們要計算子樹uuudpdpdp值的時候,其兒子節點分別為v1,v2,...,vmv_1,v_2,...,v_mv1?,v2?,...,vm?.

如果我們將通向兒子節點vvv的某條邊切斷,那么這個兒子對uuu節點聯通塊大小的貢獻就沒了,但是它的方案數可以取dp[v][1..k]dp[v][1..k]dp[v][1..k],這也就是我們定義dp[v][0]dp[v][0]dp[v][0]的意義所在了,很巧妙地,dp[v][0]dp[v][0]dp[v][0]就剛好等于兒子vvvuuu的聯通塊貢獻為000時的方案數.

那么方程就得到了

dp[u][i]=∑t1+t2+...+tm=i?1dp[v1][t1]?dp[v2][t2]?...?dp[vm][tm]dp[u][i] = \sum_{t_1+t_2+...+t_m=i-1}dp[v_1][t_1]*dp[v_2][t_2]*...*dp[v_m][t_m]dp[u][i]=t1?+t2?+...+tm?=i?1?dp[v1?][t1?]?dp[v2?][t2?]?...?dp[vm?][tm?]

最后答案就是dp[1][0]dp[1][0]dp[1][0]

實現方式

我們可以先將v1v_1v1?uuu合并,再將v2v_2v2?uuu合并…

代碼

#include <iostream> #include <vector> #include <cstring> #include <algorithm> const int N = 2018; typedef long long LL; const LL P = 998244353; std::vector<int> edge[N]; LL dp[N][N]; LL tmp[N]; int sz[N]; int n,k; void dfs(int u,int fa) {sz[u] = 1;dp[u][1] = 1;for(int v : edge[u]) {if(v == fa) continue;dfs(v,u);memset(tmp,0,sizeof(tmp));for(int i = 1;i <= sz[u];++i) {for(int j = 0;j <= sz[v] && i + j <= k;++j) {tmp[i+j] = (tmp[i+j] + (dp[u][i] * dp[v][j] % P)) % P;}}for(int i = 1;i <= k;++i)dp[u][i] = tmp[i];sz[u] += sz[v];}for(int i = 1;i <= k;++i)dp[u][0] = (dp[u][0] + dp[u][i]) % P; } int main () {std::ios::sync_with_stdio(false);std::cin >> n >> k;for(int i = 0;i < n-1;++i) {int u,v;std::cin >> u >> v;edge[u].push_back(v);edge[v].push_back(u);}dfs(1,0);std::cout << dp[1][0] << std::endl;return 0; }

D.綠膜法師

題目

題解

對于剛加入的數xxx來說,它與集合中其它的數字的gcdgcdgcd必然是它的約數.
那么枚舉xxx的約數ddd,其它的數如果與xxxgcd=dgcd = dgcd=d的話,那么其它的數必然也要有約數ddd.因此我們考慮維護一個數組muls[i]muls[i]muls[i],表示集合中的數是iii的倍數的有多少個數.

從大到小枚舉xxx的約數ddd,然后muls[d]muls[d]muls[d]就表示與xxxgcd=dgcd=dgcd=d的數的個數.隨后枚舉ddd的約數d2d_2d2?,并muls[d2]?=muls[d]muls[d2]-=muls[d]muls[d2]?=muls[d],這樣的話就保證了剛剛用過的數不會重復使用(相當于容斥一下,倒序dpdpdp的感覺).依次類推,注意刪掉的數在下一個數加入集合之前要加回來,恢復現場.

100000100000100000內的數最多有128128128個約數.
每個數的約數的約數個數和最大不超過2835每個數的約數的約數個數和最大不超過28352835
時間復雜度不會超過100000?2835=3e8100000*2835=3e8100000?2835=3e8.總之O(能過)O(能過)O().

代碼

#include <iostream> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <queue> #define pr(x) std::cout << #x << ':' << x << std::endl #define rep(i,a,b) for(int i = a;i <= b;++i) typedef long long LL; const int N = 100007; std::vector<int> ds[N]; LL mod_pow(LL x,LL n,LL p) {LL res = 1;while(n) {if(n&1) res = res * x % p;x = x * x % p;n >>= 1;}return res; } void sieve() {for(int i = 1;i <= 100000;++i) {for(int j = 1;j*j <= i;++j) {if(i % j != 0) continue;ds[i].push_back(j);if(j*j != i) ds[i].push_back(i/j);}std::sort(ds[i].begin(),ds[i].end(),[](int a,int b){return a > b;});} } LL muls[N]; int n; int main() {sieve();std::ios::sync_with_stdio(false);std::cin >> n;while(n--) {LL x,k,p;std::cin >> x >> k >> p;for(auto t : ds[x]) muls[t] ++;LL ans = 0;std::queue<int> Q;for(auto t : ds[x]) {ans = (ans + muls[t]*mod_pow(t,k,p)) % p;int tmp = muls[t];Q.push(tmp);for(auto ft : ds[t]) {muls[ft] -= tmp;}}for(auto t : ds[x]) {int tmp = Q.front();Q.pop();for(auto ft : ds[t])muls[ft] += tmp;}std::cout << ans << std::endl;}return 0; }

總結

以上是生活随笔為你收集整理的Wannafly 挑战赛27 题解的全部內容,希望文章能夠幫你解決所遇到的問題。

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