模擬賽41 題解
阿新 • • 發佈:2020-11-27
T1
考場上一看到暴力有70分就沒有去想正解。當時腦子裡閃過了先處理兩個相加,再詢問。但是當時感覺可能會算重複,就沒有繼續往下想。
但是應該是沒有重複的。因為順序不同也算不同方案。。
因為100000內的質數只有9000多個,所以可以定義dp[i]為i能被兩個質數相加得到的方案數。然後\(n^2\)求出。
對於每個n,只需O(n)求出答案即可。
程式碼:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=100000+10; int read(){ int w=0,x=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') x=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ w=(w<<1)+(w<<3)+(ch^48); ch=getchar(); } return x*w; } int n,cnt; int prime[maxn]; bool is_not_prime[maxn]; ll dp[maxn<<1]; ll ans; void xxs(){ is_not_prime[0]=is_not_prime[1]=1; for(register int i=2;i<=100000;++i){ if(!is_not_prime[i]) prime[++cnt]=i; for(register int j=1;j<=cnt&&i*prime[j]<=100000;++j){ is_not_prime[prime[j]*i]=1; if(i%prime[j]==0) break; } } for(register int i=1;i<=cnt;++i){ for(register int j=1;j<=cnt;++j){ if(prime[i]+prime[j]<=100000) dp[prime[i]+prime[j]]++; } } } void Solve(){ xxs(); int T=read(); while(T--){ n=read(); ll ans=0; for(register int i=1;i<=n;++i) ans+=dp[i]*dp[n-i]; printf("%lld\n",ans); } } int main(){ freopen("plus.in","r",stdin); freopen("plus.out","w",stdout); Solve(); return 0; }
T2
轉化為01trie。發現對於[l,r],假如兩個區間[l,mid],[mid+1,r]完全相同,那麼就是這一位取0或1都行於是返回F(l,mid)2。
如果兩個區間沒有交,那麼就是分開討論,再相乘,即F(l,mid+1)F(mid+1,r);
如果兩種情況都沒出現,那麼一定無解。
邊界F(x,x)=1;
(其實可以先在OJ上交一發printf('0');,然後發現0分,證明沒有無解的情況,於是每次比較兩個區間的時候只需要比較第一個元素即可,然後就跑成了最優解233)
程式碼:
#include <bits/stdc++.h> using namespace std; const int maxn=1<<17,mod=1e9+7; #define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++) #define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = gc();} while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; }) char buf[1 << 20], *p1, *p2; int m,n; int p[maxn]; int ans; int Devide(int l,int r){ if(l==r) return 1; int mid=(l+r)>>1; bool flag=0; if(p[l]==p[mid+1]) return 2*Devide(l,mid)%mod; return 1ll*Devide(l,mid)*Devide(mid+1,r)%mod; } void Solve(){ m=read(); n=read(); for(int i=1;i<=(1<<m);++i) p[i]=read(); ans=Devide(1,1<<m); printf("%d\n",ans); } int main(){ freopen("match.in","r",stdin); freopen("match.out","w",stdout); Solve(); return 0; }
T3
這題轉化完了之後竟然是原題。。操
發現一條邊是黑邊的條件,就是兩個端點被不同的修改操作修改過。
因此可以打時間戳,最後詢問路徑有多少連續相等的段。
於是就是luogu P2486 [SDOI2011]染色了,具體怎麼維護連結裡有。
程式碼:
#include <bits/stdc++.h> using namespace std; const int maxn=500000+10,Inf=0x3f3f3f3f; struct node{ int to,next; }edge[maxn<<1]; int head[maxn],top[maxn],size[maxn],son[maxn],fa[maxn],depth[maxn],dfn[maxn]; int n,m,cnt,Time,tim; struct Segment_tree{ int val,lazy,lc,rc;//lc,rc分別表示這個區間左右端點的color,lazy==-1時表示沒有賦值 }tree[maxn<<2]; int read(){ int w=0,x=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') x=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ w=(w<<1)+(w<<3)+(ch^48); ch=getchar(); } return x*w; } void add(int from,int to){ edge[++cnt].to=to; edge[cnt].next=head[from]; head[from]=cnt; } void dfs1(int u,int f){ size[u]=1; fa[u]=f; for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to; if(v==f) continue; depth[v]=depth[u]+1; dfs1(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]) son[u]=v; } } void dfs2(int u,int t){ top[u]=t; dfn[u]=++Time; if(son[u]) dfs2(son[u],t); for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } void pushup(int rt){ tree[rt].lc=tree[rt<<1].lc; tree[rt].rc=tree[rt<<1|1].rc; tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val-(tree[rt<<1].rc==tree[rt<<1|1].lc); } void update(int rt,int x){ tree[rt].lazy=x; tree[rt].val=1; tree[rt].lc=tree[rt].rc=x; } void pushdown(int rt){ if(tree[rt].lazy==-1) return; tree[rt].val=1; update(rt<<1,tree[rt].lazy); update(rt<<1|1,tree[rt].lazy); tree[rt].lazy=-1; } void modify(int rt,int l,int r,int s,int t,int p){ if(s<=l&&r<=t){ update(rt,p); return; } int mid=(l+r)>>1; pushdown(rt); if(s<=mid) modify(rt<<1,l,mid,s,t,p); if(t>mid) modify(rt<<1|1,mid+1,r,s,t,p); pushup(rt); } void build(int rt,int l,int r){ tree[rt].lazy=-1; if(l==r){ tree[rt].val=1; tree[rt].lc=tree[rt].rc=l; return; } int mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); pushup(rt); } int query2(int rt,int l,int r,int x){ if(l==r) return tree[rt].lc; int mid=(l+r)>>1; pushdown(rt); if(x<=mid) return query2(rt<<1,l,mid,x); else return query2(rt<<1|1,mid+1,r,x); } int query(int rt,int l,int r,int s,int t){ if(s<=l&&r<=t) return tree[rt].val; int mid=(l+r)>>1; pushdown(rt); if(t<=mid) return query(rt<<1,l,mid,s,t); if(s>mid) return query(rt<<1|1,mid+1,r,s,t); return query(rt<<1,l,mid,s,t)+query(rt<<1|1,mid+1,r,s,t)-(tree[rt<<1].rc==tree[rt<<1|1].lc); } int Query(int u,int v){ if(u==v) return 1; int res=0; while(top[u]!=top[v]){ if(depth[top[u]]<depth[top[v]]) swap(u,v); //printf("u==%d v==%d\n",u,v); res+=query(1,1,n,dfn[top[u]],dfn[u]); //printf("dfn[top[u]]=%d dfn[u]=%d\n",dfn[top[u]],dfn[u]); if(top[u]!=1){ int sss=query2(1,1,n,dfn[top[u]]); int ssss=query2(1,1,n,dfn[fa[top[u]]]); //printf("sss=%d ssss=%d\n",sss,ssss); if(sss==ssss) res--; //if(top[u]!=1 && query2(1,1,n,dfn[top[u]])==query2(1,1,n,dfn[fa[top[u]]])) res--; } u=fa[top[u]]; } if(depth[u]>depth[v]) swap(u,v); res+=query(1,1,n,dfn[u],dfn[v]); return res; } void Modify(int u,int v,int x){ while(top[u]!=top[v]){ if(depth[top[u]]<depth[top[v]]) swap(u,v); modify(1,1,n,dfn[top[u]],dfn[u],x); u=fa[top[u]]; } if(depth[u]>depth[v]) swap(u,v); modify(1,1,n,dfn[u],dfn[v],x); } void Solve(){ n=read(); for(int i=1,x,y;i<n;++i){ x=read(); y=read(); add(x,y); add(y,x); } dfs1(1,0); dfs2(1,1); build(1,1,n); //for(int i=1;i<=n;++i) printf("fa[%d]=%d son[%d]=%d depth[%d]=%d top[%d]=%d size[%d]=%d dfn[%d]=%d\n",i,fa[i],i,son[i],i,depth[i],i,top[i],i,size[i],i,dfn[i]); m=read(); tim=n; for(int i=1,op,x,y,z;i<=m;++i){ op=read(); x=read(); y=read(); if(op==0){ int res=Query(x,y); printf("%d\n",res-1); } else{ tim++; Modify(x,y,tim); } } } int main(){ freopen("colour.in","r",stdin); freopen("colour.out","w",stdout); Solve(); return 0; }
T4
不會