Noip模拟6 2021.6.10
T1 辣鸡
首先吐嘈一下,这题的测试点就离谱,不说了,附上我65分代码:
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 inline int read(){ 5 int x=0,f=1; char ch=getchar(); 6 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 7 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 8 return x*f; 9 } 10 int n,wsn; 11 namespace WSN{ 12 inline int main(){ 13 n=read(); 14 for(int i=1;i<=n;i++){ 15 int x1=read(),y1=read(),x2=read(),y2=read(); 16 int a=x2-x1,b=y2-y1; 17 wsn+=a*b*2; 18 } 19 printf("%lld\n",wsn); 20 return 0; 21 } 22 } 23 signed main(){return WSN::main();}
震撼我,这不相邻的矩形咋这么多!!!
但是当时没有敢打,可惜可惜。。
然而这题正解也是暴力,所以就不说什么了,上代码
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 inline int read(){ 5 int x=0,f=1; char ch=getchar(); 6 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 7 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 8 return x*f; 9 } 10 int n,wsn; 11 struct SNOW{int x1,y1,x2,y2;};SNOW s[100005]; 12 bool cmp(SNOW a,SNOW b){return a.x1<b.x1;} 13 namespace WSN{ 14 inline int main(){ 15 n=read(); 16 for(int i=1;i<=n;i++){ 17 s[i].x1=read();s[i].y1=read();s[i].x2=read();s[i].y2=read(); 18 wsn+=(s[i].x2-s[i].x1)*(s[i].y2-s[i].y1)*2; 19 } 20 sort(s+1,s+n+1,cmp); 21 for(int i=1;i<n;i++){ 22 for(int j=i+1;j<=n;j++){ 23 if(s[j].x1-s[i].x2>1) break; 24 if(min(s[i].x2,s[j].x2)-max(s[i].x1,s[j].x1)>=0){ 25 if(s[j].y1-s[i].y2==1){ 26 wsn+=(min(s[i].x2,s[j].x2)-max(s[i].x1,s[j].x1))*2; 27 if(s[i].x1!=s[j].x1) wsn++; 28 if(s[j].x2!=s[i].x2) wsn++; 29 } 30 if(s[i].y1-s[j].y2==1){ 31 wsn+=(min(s[i].x2,s[j].x2)-max(s[i].x1,s[j].x1))*2; 32 if(s[i].x1!=s[j].x1) wsn++; 33 if(s[j].x2!=s[i].x2) wsn++; 34 } 35 } 36 if(min(s[i].y2,s[j].y2)-max(s[i].y1,s[j].y1)>=0){ 37 if(s[j].x1-s[i].x2==1){ 38 wsn+=(min(s[i].y2,s[j].y2)-max(s[i].y1,s[j].y1))*2; 39 if(s[i].y1!=s[j].y1) wsn++; 40 if(s[j].y2!=s[i].y2) wsn++; 41 } 42 if(s[i].x1-s[j].x2==1){ 43 wsn+=(min(s[i].y2,s[j].y2)-max(s[i].y1,s[j].y1))*2; 44 if(s[i].y1!=s[j].y1) wsn++; 45 if(s[j].y2!=s[i].y2) wsn++; 46 } 47 } 48 if(s[j].x1-s[i].x2==1&&(s[j].y1-s[i].y2==1||s[i].y1-s[j].y2==1)) wsn++; 49 } 50 } 51 printf("%lld\n",wsn); 52 return 0; 53 } 54 } 55 signed main(){return WSN::main();}
T2 模板(线段树合并)
这题目暴力很好想注意一下细节就可以很好拿到30分了,然而我现在还没有学习线段树合并,就先贴上暴力代码了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 inline int read(){ 4 int x=0,f=1; char ch=getchar(); 5 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 6 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 7 return x*f; 8 } 9 const int NN=1e5+10; 10 int n,m,q,fa[NN],k[NN]; 11 bool v[NN],typ[NN]; 12 vector<int> co[NN]; 13 struct SNOW{ int to,next;}; SNOW g[NN<<1]; int r[NN<<1],tot; 14 inline void add(int x,int y){g[++tot]=(SNOW){y,r[x]}; r[x]=tot;} 15 inline void dfs1(int x){ 16 v[x]=true; 17 for(int i=r[x];i;i=g[i].next) 18 if(!v[g[i].to]){ 19 fa[g[i].to]=x; 20 dfs1(g[i].to); 21 } 22 } 23 inline void dfs2(int x,int val){ 24 if(k[x]>0) co[x].push_back(val); 25 k[x]--; 26 if(!fa[x]) return; 27 dfs2(fa[x],val); 28 } 29 namespace WSN{ 30 inline int main(){ 31 n=read(); 32 for(int i=1;i<n;i++){ 33 int u=read(),v=read(); 34 add(u,v); add(v,u); 35 } 36 dfs1(1); 37 for(int i=1;i<=n;i++) k[i]=read(); 38 m=read(); 39 for(int i=1;i<=m;i++){ 40 int x=read(),c=read(); 41 dfs2(x,c); 42 } 43 q=read(); 44 for(int i=1;i<=q;i++){ 45 memset(typ,false,sizeof(typ)); 46 int x=read(),maxn=0,minn=0x3fffffff; 47 for(int j=0;j<co[x].size();j++){ 48 typ[co[x][j]]=true; 49 maxn=max(co[x][j],maxn); 50 minn=min(co[x][j],minn); 51 } 52 int wsn=0; 53 for(int j=minn;j<=maxn;j++){ 54 if(typ[j]) wsn++; 55 } 56 printf("%d\n",wsn); 57 } 58 return 0; 59 } 60 } 61 signed main(){return WSN::main();}
回来补坑,线段树以时间开,在启发式合并的时候判断时间和颜色的先后位置,然后在合并。
1 #include<bits/stdc++.h> 2 #define mid ((l+r)>>1) 3 using namespace std; 4 inline int read(){ 5 int x=0,f=1; char ch=getchar(); 6 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 7 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 8 return x*f; 9 10 } 11 12 const int NN=1e5+10; 13 int n,m,q,k[NN]; 14 vector<int> vc[NN]; 15 int rt[NN]; 16 int son[NN],ans[NN],siz[NN]; 17 18 struct snow{int x,c;}; snow wk[NN]; int dis[NN],m_new; 19 struct SNOW{ int to,next;}; SNOW e[NN<<1]; int head[NN],tot; 20 inline void add(int x,int y){e[++tot]=(SNOW){y,head[x]}; head[x]=tot;} 21 22 inline void discrete(){ 23 sort(dis+1,dis+m+1); m_new=unique(dis+1,dis+m+1)-dis-1; 24 for(int i=1;i<=m;i++){ 25 wk[i].c=lower_bound(dis+1,dis+m_new+1,wk[i].c)-dis; 26 vc[wk[i].x].push_back(i); 27 } 28 } 29 30 inline void init(){ 31 n=read(); 32 for(int i=1;i<n;i++){ 33 int u=read(),v=read(); 34 add(u,v); add(v,u); 35 } 36 for(int i=1;i<=n;i++) k[i]=read(); 37 m=read(); 38 for(int i=1;i<=m;i++) wk[i].x=read(),dis[i]=wk[i].c=read(); 39 discrete(); 40 } 41 42 struct SNOWtree{ 43 int seg,ls[NN*80],rs[NN*80]; 44 int sum[NN*80],kin[NN*80];//颜色数量 颜色种类 45 int pre[NN*80],fro[NN*80],rp; //第一次出现的时间 第一个颜色出现的种类 颜色个数 46 47 inline void insert(int &x,int l,int r,int pos,int kind,int v){ 48 if(!x) x=++seg; 49 if(l==r) {sum[x]=v; kin[x]=kind; return;} 50 if(pos<=mid) insert(ls[x],l,mid,pos,kind,v); 51 else insert(rs[x],mid+1,r,pos,kind,v); 52 sum[x]=sum[ls[x]]+sum[rs[x]]; 53 kin[x]=kin[ls[x]]+kin[rs[x]]; 54 } 55 56 inline void gather(int x,int t,int co){//节点 时间 颜色 57 if(!pre[co]){ 58 fro[++rp]=co; 59 pre[co]=t; 60 insert(rt[x],1,m,t,1,1); 61 return; 62 } 63 if(pre[co]<t){ insert(rt[x],1,m,t,0,1); return; } 64 if(pre[co]>t){ 65 insert(rt[x],1,m,t,1,1); 66 insert(rt[x],1,m,pre[co],0,1); 67 pre[co]=t; return; 68 } 69 } 70 71 inline void merge(int x,int l,int r,int p){ 72 if(!x) return; 73 if(l==r&&sum[x]){ gather(p,l,wk[l].c); return; } 74 merge(ls[x],l,mid,p); 75 merge(rs[x],mid+1,r,p); 76 } 77 78 inline int query(int x,int l,int r,int res){ 79 if(!x||!res) return 0; 80 if(l==r) return kin[x]; 81 int an=0; 82 if(ls[x]&&res<sum[ls[x]]) an+=query(ls[x],l,mid,res); 83 else{ 84 an+=kin[ls[x]]; 85 an+=query(rs[x],mid+1,r,res-sum[ls[x]]); 86 } 87 return an; 88 } 89 90 inline void clear(){ while(rp) pre[fro[rp--]]=0; }//只清空有数的 91 92 }tr; 93 94 inline void find_heavyson(int f,int x){ 95 siz[x]=vc[x].size()+1; 96 for(int i=head[x];i;i=e[i].next){ 97 if(e[i].to==f) continue; 98 int y=e[i].to; 99 find_heavyson(x,y); 100 siz[x]+=siz[y]; 101 if(siz[y]>siz[son[x]]) son[x]=y; 102 } 103 } 104 105 inline void dfs(int f,int x){ 106 for(int i=head[x];i;i=e[i].next){ 107 int y=e[i].to; 108 if(y==f||y==son[x]) continue; 109 dfs(x,y); tr.clear(); 110 } 111 if(son[x]) dfs(x,son[x]); 112 rt[x]=rt[son[x]]; 113 for(int i=0;i<vc[x].size();i++) 114 tr.gather(x,vc[x][i],wk[vc[x][i]].c); 115 for(int i=head[x];i;i=e[i].next){ 116 int y=e[i].to; 117 if(y==f||y==son[x]) continue; 118 tr.merge(rt[y],1,m,x); 119 } 120 ans[x]=tr.query(rt[x],1,m,k[x]); 121 } 122 123 namespace WSN{ 124 inline int main(){ 125 init(); 126 find_heavyson(0,1); 127 dfs(0,1); 128 q=read(); 129 for(int i=1;i<=q;i++) printf("%d\n",ans[read()]); 130 return 0; 131 } 132 } 133 signed main(){return WSN::main();}
T3 大佬(概率与期望)
首先,这题分数取莫,想到用费马小定理求逆元
然后就是推柿子:
$ans=\frac{\sum\limits_{i=1}^{m}g(i)*w[i]}{m^k}*(n-k+1)$
此柿子何来?
$g[x]=x^k-(x-1)^k$
每道题有x种选择,要除掉不合法的状态,即最大难度不是x,根据容斥可得。
然而仔细推一下可以发现他的每一个项都是由递推得到的,则代码:
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 inline int read(){ 5 int x=0,f=1; char ch=getchar(); 6 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 7 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 8 return x*f; 9 } 10 const int NN=505,p=1000000007; 11 int n,m,k,phi,sum,res,w[NN],a[NN]; 12 inline int fima(int a,int b){ 13 int ans=1; a%=p; 14 while(b){ 15 if(b&1) ans=(ans*a)%p; 16 b>>=1; a=(a*a)%p; 17 } return ans; 18 } 19 namespace WSN{ 20 inline int main(){ 21 n=read(); m=read(); k=read(); 22 if(n<k) {printf("0\n");return 0;} 23 for(int i=1;i<=m;i++) w[i]=read(); 24 phi=fima(fima(m,k),p-2); 25 for(int i=1;i<=m;i++){ 26 a[i]=(fima(i,k)-sum+p)%p; 27 sum=(sum+a[i])%p; 28 } 29 for(int i=1;i<=m;i++) res=(res+a[i]*w[i]%p)%p; 30 printf("%lld\n",(n-k+1)*res%p*phi%p); 31 return 0; 32 } 33 } 34 signed main(){return WSN::main();}
T4 宝藏(状压dp)
看到这数据,是不是想状压,而且二维数组求距离还特别方便,现在这么一想,感觉还是比较水的
代码表现的非常明白,是一个按层推的思想。这样dp才可以找到dian的加和值
1 #include<bits/stdc++.h> 2 using namespace std; 3 inline int read(){ 4 int x=0,f=1; char ch=getchar(); 5 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 6 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 7 return x*f; 8 } 9 int n,m,k,wsn=0x3fffffff,f[13][1<<12],dis[13][13],g[13][13]; 10 inline void dfs(int st,int x){ 11 for(int i=1;i<=n;i++){ 12 if(!(x&(1<<i-1))) continue; 13 for(int j=1;j<=n;j++){ 14 if(x&(1<<j-1)) continue; 15 if(g[i][j]==999999999) continue; 16 if(f[st][x|(1<<j-1)]>f[st][x]+dis[st][i]*g[i][j]){ 17 f[st][x|(1<<j-1)]=f[st][x]+dis[st][i]*g[i][j]; 18 dis[st][j]=dis[st][i]+1; 19 dfs(st,x|(1<<j-1)); 20 } 21 } 22 } 23 } 24 namespace WSN{ 25 inline int main(){ 26 memset(f,0x3f,sizeof(f)); 27 for(int i=0;i<=12;i++) 28 for(int j=0;j<=12;j++) g[i][j]=999999999; 29 n=read(),m=read(); 30 for(int i=1;i<=m;i++){ 31 int x=read(),y=read(),z=read(); 32 if(z<g[x][y]) g[x][y]=g[y][x]=z; 33 } 34 for(int i=1;i<=n;i++){ 35 f[i][1<<i-1]=0; 36 dis[i][i]=1; 37 dfs(i,1<<i-1); 38 wsn=min(wsn,f[i][(1<<n)-1]); 39 } 40 printf("%d\n",wsn); 41 return 0; 42 } 43 } 44 signed main(){return WSN::main();}
END
这次考试没什么超长发挥的地方,还是有很多遗憾的,比如第一题最基础的五分没拿到手等等,下次考试还是要注意时间分配,尽量每题都有分吧~~~

浙公网安备 33010602011771号