[jzoj NOIP2018模拟 11.01]
很慶幸打了這場模擬賽,因為這一場爆零
好像上次紀中的某場比賽我也出現了同樣的問題,光是計算時間復雜度而忘記了空間的限制。想必是比上次慘的,考場上就寫了兩題而這兩題都因為MLE爆零了。而且我T2還碼了7k自信滿滿可以A掉,但實際上因為常數太大解決掉MLE的鍋之后也只有50分,以后大概要失去在考場上碼300多行的勇氣了。
不多講了寫題解吧
T1:乘?
題目鏈接:
https://jzoj.net/senior/#contest/show/2545/0
題目:
題解:
考場上歐拉定理玩來玩去就是想不出,沒想到正解居然如此...easy
我們要計算$a^b$,而$b<=1e12$。我們令$N=1e6,A=b%N,B=b/N$,顯然答案就是$a^Aa^{BN}$。
于是我們可以預處理$a$的次冪和$a^N$的次冪,$O(1)$查詢就是了
#include<algorithm> #include<cstring> #include<iostream> #include<cstdio> using namespace std; typedef long long ll;const int N=1e6; ll a,p,q,k,b0,l,m,c; ll pin[N+15],bin[N+15]; ll qpow(ll a,ll b) {ll re=1;for (;b;b>>=1,a=a*a%p) if (b&1) re=re*a%p;return re; } int main() {freopen("pow.in","r",stdin);freopen("pow.out","w",stdout);scanf("%lld%lld%lld%lld",&a,&p,&q,&k);scanf("%lld%lld%lld%lld",&b0,&l,&m,&c);pin[0]=1;for (int i=1;i<=N;i++) pin[i]=pin[i-1]*a%p;ll aa=qpow(a,N);bin[0]=1;for (int i=1;i<=N;i++) bin[i]=bin[i-1]*aa%p;ll ans=0;for (int i=1;i<=q;i++){b0=(m*b0+c)%l;ll A=b0/N,B=b0%N;ans=ans^(bin[A]*pin[B]%p);if (i%k==0) printf("%lld\n",ans);}return 0; } View CodeT2:樹?
題目鏈接:
https://jzoj.net/senior/#contest/show/2545/1
題目:
題解:
嘖一看到按位與就陷入了自帶常數32的怪圈,我打包票如果時間開成5s我的考場代碼可以A掉
然后并不需要這個常數
發現按位與只會讓數值變小,每個元素只會變小$log$次。我們只需要維護區間的或來判斷當前與的值是否會對區間內的某個元素產生影響,如果有的話就暴力遞歸下去就是了
那個期望什么的就是把平方和的算式拆開,發現只需要維護一下區間和和區間平方和就可以了。由于上面那個操作是單點修改,一切都是那么的和諧
時間復雜度$O(nlog^2n)$
#include<algorithm> #include<cstring> #include<cstdio> #include<iostream> using namespace std; typedef long long ll;const int N=1e5+15; const ll mo=998244353; int n; ll a[N],t[N<<2],sf[N<<2],s[N<<2]; inline int read(){char ch=getchar();int s=0,f=1;while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}return s*f; } #define mid ((l+r)>>1) void pushup(int o) {t[o]=t[o<<1]|t[o<<1|1];s[o]=s[o<<1]+s[o<<1|1]; sf[o]=(sf[o<<1]+sf[o<<1|1])%mo; } void build(int o,int l,int r) {if (l==r){t[o]=a[l];s[o]=a[l];sf[o]=a[l]*a[l]%mo;return;}build(o<<1,l,mid);build(o<<1|1,mid+1,r);pushup(o); } bool ck(ll a,ll b) {for (int j=0;j<32;j++) if ((!(b>>j&1))&&(a>>j&1)) return 0;return 1; } void update(int o,int l,int r,int x,int y,ll k) {if (l==r){t[o]&=k;s[o]&=k;sf[o]=s[o]*s[o]%mo;return;}if (l>=x&&r<=y){if (ck(t[o],k)) return;}if (x<=mid) update(o<<1,l,mid,x,y,k);if (y>mid) update(o<<1|1,mid+1,r,x,y,k);pushup(o); } ll query(int o,int l,int r,int x,int y) {if (l>=x&&r<=y) return s[o];ll re=0;if (x<=mid) re=re+query(o<<1,l,mid,x,y);if (y>mid) re=re+query(o<<1|1,mid+1,r,x,y);return re; } ll que(int o,int l,int r,int x,int y) {if (l>=x&&r<=y) return sf[o];ll re=0;if (x<=mid) re=(re+que(o<<1,l,mid,x,y));if (y>mid) re=(re+que(o<<1|1,mid+1,r,x,y));return re; } int main() {freopen("seg.in","r",stdin);freopen("seg.out","w",stdout);n=read();for (int i=1;i<=n;i++) a[i]=read();build(1,1,n);int q=read();int op,l,r,k;while (q--){op=read();l=read();r=read();if (op==1){k=read();update(1,1,n,l,r,k);}if (op==2){printf("%lld\n",query(1,1,n,l,r));}if (op==3){ll S1=query(1,1,n,l,r)%mo;ll S2=que(1,1,n,l,r);ll ans=(2*S2%mo*(r-l+1)%mo+2*S1%mo*S1%mo)%mo;printf("%lld\n",ans);}}return 0; } View CodeT3:信標?
題目鏈接:
https://jzoj.net/senior/#contest/show/2545/2
題目:
題解:
以下來自題解
?設一個節點有 c 個兒子, 發現必須在其中至少 c ? 1 個兒子的子樹中放置信標.
證明如下: 考慮如果不這樣放, 對于兩棵都沒有放的子樹, 他們匯集到 lca 上以后距離都是相等的, 所以 lca 外的信標無法區分, 而內部沒有信標. 所以不能存在兩顆子樹都不放. 所以至少要放 c ? 1 個. 由于在根節點放置了信標, 可以只考慮深度相同的點. 由于深度相同, 所以他們的 lca 度數至少 為 2, 那么一定有一個信標在 lca 包含這兩個點的兩支子樹中. 那么另一側的點肯定要走更遠的路, 會被區分開. 所以放 c ? 1 個足夠區分.
這樣問題變成每個節點要有 c ? 1 棵子樹放有信標, 求最小方案. 直接貪心即可. 由于枚舉根所 以復雜度為 $O(n^2 )$, 可以獲得 70 分.
如何做到$ O(n)$? 我們先特判鏈的情況答案為 1, 然后找到任意一個度數大于 2 的節點, 可以證 明這個點一定不需要放置信標. 于是以這個點作根$ O(n) $的貪心即可.
證明如下: 深度相同的點對證明同上, 只考慮深度不同的點對.
如果它們在一顆子樹中, 由于度數大于 2 所 以一定有另一顆子樹的一個信標把他們區分開.
如果在不同的子樹中, 有兩種情況:
一個在沒放信標的子樹中, 一個在放了的子樹中. 顯然還存在另一個子樹放了信標, 由于深度不 同他們會被這個信標區分開.
兩個都在放了信標的子樹中. 如果根的度數大于 3 則同上. 度數等于 3 時, 如果他們沒有被區分 開, 一定是他們先匯集到了一個節點上, 然后走到同一個信標上. 這個點一定是一條奇鏈的中點, 且 不是根 (由于深度不同), 是在兩個子樹之一中唯一的. 那么他們走到另一個信標就一定有一個點走 了冤枉路, 既另一個信標可以區分出他們.
#include<algorithm> #include<cstring> #include<cstdio> #include<iostream> using namespace std;const int N=1e6+15; const int inf=1e9; int n,tot; int head[N],f[N],deg[N]; struct EDGE{int to,nxt; }edge[N<<1]; inline int read(){char ch=getchar();int s=0,f=1;while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}return s*f; } void link(int u,int v){edge[++tot]=(EDGE){v,head[u]};head[u]=tot;} void dfs(int x,int pre) {int cnt=0,s=0,p0=0;for (int i=head[x];i;i=edge[i].nxt){int y=edge[i].to;if (y==pre) continue;dfs(y,x); s+=f[y];if (f[y]==0) p0++;++cnt;}if (cnt==0) {f[x]=0;return;}f[x]=s;if (p0>=1) f[x]+=p0-1; } int main() {freopen("beacon.in","r",stdin);freopen("beacon.out","w",stdout);n=read();if (n==1) {puts("0");return 0;}for (int i=1,u,v;i<n;i++){u=read();v=read();link(u,v);link(v,u);deg[u]++;deg[v]++;}int s=0;for (int i=1;i<=n;i++) if (deg[i]>=3) s=i;if (!s) {puts("1");return 0;}dfs(s,-1);printf("%d\n",f[s]);return 0; } View Code轉載于:https://www.cnblogs.com/xxzh/p/9891453.html
總結
以上是生活随笔為你收集整理的[jzoj NOIP2018模拟 11.01]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 洛谷P1396 营救 题解
- 下一篇: 简述systemd的新特性及unit常见