【题解】CF1817 合集
CF1817A Almost Increasing Subsequence
标签:思维题
考虑几乎上升的序列的长度,就是我们的区间长度减去
code:
#include<bits/stdc++.h> using namespace std; const int NN = 2e5 + 8; int n,q; int a[NN]; int pre[NN],cnt[NN],ck[NN]; int main(){ // freopen("1.out","w",stdout); scanf("%d%d",&n,&q); for(int i = 1; i <= n; ++i) scanf("%d",&a[i]); for(int i = 1; i <= n; ++i){ if(i < n && a[i] >= a[i+1]) pre[i] = 1,ck[i] = 1; if(i < n && a[i] >= a[i+1] && a[i-1] < a[i]) cnt[i] = 1; pre[i] += pre[i-1]; cnt[i] += cnt[i-1]; } // for(int i = 1; i <= n; ++i) printf("%d ",pre[i]);puts(""); // for(int i = 1; i <= n; ++i) printf("%d ",cnt[i]);puts(""); while(q--){ int l,r; scanf("%d%d",&l,&r); if(l == r){puts("1");continue;} if(l == r-1){puts("2");continue;} printf("%d\n",(r-l+1) - (pre[r-1] - pre[l-1]) + (cnt[r-1] - cnt[l] + ck[l])); } }
CF1817B Fish Graph
我们的目的就是找到一个环,且环上的其中一个点至少和环外两个的点有边相连。
我们考虑我们肯定不能把所有的环都找一遍,这样一定会 TLE
。
那么我们该怎么做呢?
我们可以发现一个性质,就是一个环上如果有度数大于等于
我们就可以从度数大于等于
- 我们搜到了一条连向当前搜索树的根的返祖边,那么我们一定能找到一个环上只包含。时间复杂度
- 我们搜不到一条连向当前搜索树的根的返祖边,那么这个点就不在任意一条环上。时间复杂度
因为我们只需要找到一个满足要求的环即可,所以总的时间复杂度为
code:
#include<bits/stdc++.h> using namespace std; const int NN = 2e3 + 8; int t,n,m; int sta[NN],top,gt; bool vis[NN],col[NN]; int du[NN]; struct Edge{ int to,next; }edge[NN << 1]; int head[NN],cnt; void init(){ for(int i = 0; i <= n; ++i) head[i] = -1,vis[i] = 0,du[i] = 0; cnt = 1;top = 0;gt = 0; } void add_edge(int u,int v){ edge[++cnt] = {v,head[u]}; head[u] = cnt; } int nowu,nowv; int eu[4],ev[4]; bool check(int u,int v){ nowu = u;nowv = v; bool res = 0; int tp = top; while(sta[tp] != u) col[sta[tp--]] = 1; col[sta[tp]] = 1; tp = top; while(sta[tp+1] != u){ int fm = sta[tp--],cnt = 0; for(int i = head[fm]; i != -1 && cnt <= 2; i = edge[i].next){ int to = edge[i].to; if(!col[to]){eu[cnt] = fm;ev[cnt++] = to;} } if(cnt >= 2) {res = 1;break;} } tp = top; while(sta[tp] != u) col[sta[tp--]] = 0; col[sta[tp]] = 0; return res; } void dfs(int u,int fae,int rt){ sta[++top] = u;vis[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next){ int v = edge[i].to; if((i^1) == fae) continue; if(v == rt){ if(check(v,u)) gt = 1; } else if(!vis[v])dfs(v,i,rt); if(gt) {vis[u] = 0;return;} } --top;vis[u] = 0; } int main(){ scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m);init(); int rt; for(int i = 1,u,v; i <= m; ++i){ scanf("%d%d",&u,&v);add_edge(u,v);add_edge(v,u); ++du[u];++du[v]; } for(int i = 1; i <= n; ++i,top = 0) { if(du[i] >= 4) dfs(i,-1,i); if(gt) break; } if(gt){ puts("YES"); int tp = top,ans = 0; while(sta[tp] != nowu) ++ans,tp--; ans += 3; printf("%d\n",ans); for(int i = tp; i < top; ++i) printf("%d %d\n",sta[i],sta[i+1]); printf("%d %d\n",sta[top],sta[tp]); printf("%d %d\n%d %d\n",eu[0],ev[0],eu[1],ev[1]); } else puts("NO"); } }
CF1817C Similar Polynomials
标签:数学
多项式次数太高了,不好处理。考虑 “求导” 降次。离散意义下就是差分。
我们知道,对函数做形如
显然,根据
至于
你考虑多项式差分的定义为:
我们可以从生成函数的角度考虑,一次差分本质上就是乘上了
时间复杂度
code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int NN = 3e6 + 8,MOD = 1e9 + 7; ll d; ll A[NN],B[NN]; ll fac[NN],inv[NN]; ll ksm(ll x,ll k){ ll res = 1; while(k){ if(k&1) res = res * x % MOD; x = x * x % MOD; k >>= 1; } return res; } ll binom(ll n,ll m){ return fac[n] * inv[m] % MOD * inv[n-m] % MOD; } int main(){ scanf("%lld",&d); fac[0] = 1; for(int i = 1; i <= d; ++i) fac[i] = fac[i-1] * i % MOD; inv[d] = ksm(fac[d],MOD - 2); for(int i = d; i >= 1; --i) inv[i-1] = inv[i] * i % MOD; for(int i = 0; i <= d; ++i) scanf("%lld",&A[i]); for(int i = 0; i <= d; ++i) scanf("%lld",&B[i]); ll k,b,res = 0; for(int i = 0; i <= d-1; ++i) res = (res + binom(d-1,i) * ((d-1-i)&1?-1:1) * A[i]) % MOD; b = res;res = 0; for(int i = 0; i <= d-1; ++i) res = (res + binom(d-1,i) * ((d-1-i)&1?-1:1) * A[i+1]) % MOD; k = res - b;res = 0; for(int i = 0; i <= d-1; ++i) res = (res + binom(d-1,i) * ((d-1-i)&1?-1:1) * B[i]) % MOD; ll s = (res - b) * ksm(k,MOD - 2) % MOD; printf("%lld",(s+MOD) % MOD); }
CF1817D Toy Machine
标签:思维题
一道很好玩的游戏题。
题目也非常良心,给了一个可以操作的网页:

option 1:我们考虑手玩一下可以发现左半部分很简单,就是 LDRU
即可,然后最后接一个 L
(下图为将 d
挪到最左边)。

关键是右半部分怎么挪动到左边?
option 2:我们发现我们可以使用 RDRU
将所有玩具都挪到最右边,然后再用一个 L
将最右边的玩具挪到最左边

option 3:现在我们就需要将右半部分的玩具挪到最右边,可以模仿挪到最右边的方法 RDLU
即可,然后最后接一个 R
(下图为将 f
挪到最右边)

我们的右边的玩具的挪动方法便出来了,就是先用该玩具通过 option 3 挪到最右边,再使用 option 2 将其挪到左半部分,最后使用 option 1 将其挪到最左边。
code:
#include<bits/stdc++.h> using namespace std; int n,k; int main(){ scanf("%d%d",&n,&k); if(k == n/2) return puts("DL"),0; if(k < n/2){ for(int i = 1; i < k; ++i) printf("LDRU");//operation 1 printf("L\n"); }//左半边 else{ for(int i = k; i < n-2; ++i) printf("RDLU");//operation 3 for(int i = 1; i <= n/2+10; ++i) printf("RDRU");//operation 2 for(int i = 1; i < n/2; ++i) printf("LDRU");//operation 1 printf("L"); }//右半边 }
本文来自博客园,作者:ricky_lin,转载请注明原文链接:https://www.cnblogs.com/rickylin/p/CF1817.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步