Noip模拟80 2021.10.18
预计得分:5
实际得分:140??????????????
T1 邻面合并
我考场上没切掉的大水题。。。。(证明我旁边的cty切掉了,并觉得很水)
然而贪心拿了六十,离谱,成功做到上一篇博客说的有勇气(也就是很菜,变成了自己瞧不起的人。。。)
思路很假,但他很真(雾)。。。
暴力枚举矩形,暴力删除这个矩形,暴力的找下一个矩形。。。。。然后六十???
唯一提高正确性的地方就在枚举矩形时一个点正序,另一个倒序。。。。
1 #include<cstdio> 2 #include<bitset> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 namespace AE86{ 8 #define fuck cout<<"fuck"<<endl 9 #define out(x) cout<<#x<<"="<<x<<endl 10 inline int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 14 }inline void write(int x,char opt='\n'){ 15 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 16 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 17 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 18 }using namespace AE86; 19 const int NN=105; 20 int n,m,g[NN][10],sum[NN][10],ans; 21 inline int getnum(int x){ 22 bool last=0; int tmp=0; 23 while(x){ 24 if((x&1)&&(!last)) ++tmp; 25 if(x&1) last=1;else last=0; 26 x>>=1; 27 } return tmp; 28 } 29 bitset<10> s[NN]; 30 inline int get(int x1,int y1,int x2,int y2){ 31 return sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]; 32 } 33 inline void clear(int x1,int y1,int x2,int y2){ 34 for(int i=x1;i<=x2;i++)for(int j=y1;j<=y2;j++)s[i][j]=0; 35 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)sum[i][j]=sum[i][j-1]+s[i][j]; 36 for(int j=1;j<=m;j++)for(int i=1;i<=n;i++)sum[i][j]+=sum[i-1][j]; 37 } 38 namespace WSN{ 39 inline short main(){ 40 freopen("merging.in","r",stdin); 41 freopen("merging.out","w",stdout); 42 n=read(); m=read(); 43 for(int i=1;i<=n;i++){ 44 for(int j=1;j<=m;j++){ 45 sum[i][j]=s[i][j]=read(); 46 } 47 } 48 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)sum[i][j]+=sum[i][j-1]; 49 for(int j=1;j<=m;j++)for(int i=1;i<=n;i++)sum[i][j]+=sum[i-1][j]; 50 // for(int i=1;i<=n;i++){ 51 // for(int j=1;j<=m;j++){ 52 // cout<<sum[i][j]<<" "; 53 // } cout<<endl; 54 // } 55 while(1){ 56 int tmp=0; 57 for(int i=1;i<=n;i++) if(s[i].none()) ++tmp; 58 if(tmp==n) break; bool flag=false; 59 for(int x1=1;!flag&&x1<=n;x1++) for(int y1=1;!flag&&y1<=m;y1++){ 60 for(int x2=n;!flag&&x2>=x1;x2--) for(int y2=m;!flag&&y2>=y1;y2--){ 61 if(get(x1,y1,x2,y2)==(x2-x1+1)*(y2-y1+1)){ 62 flag=1;++ans;clear(x1,y1,x2,y2); 63 break; 64 } 65 } 66 } 67 } 68 write(ans); 69 return 0; 70 } 71 } 72 signed main(){return WSN::main();}
正解必然是状压冻龟
设$f[i][sta]$表示处理到第$i$行,当前行的状态为$sta$的最少矩形数量
这个$sta$妙,不是题里面说的矩阵的$0/1$,而是表示从上一个$1$开始到下一个$1$的上一位这一段是被一个矩形所覆盖的
例如$1001101$,就表示被四个矩形覆盖,宽度分别为$3,1,2,1$,
预处理合法状态然后找到上下行可以合并的矩形数量,转移加上不可以合并的举行数量即可
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 namespace AE86{ 8 #define fuck cout<<"fuck"<<endl 9 #define out(x) cout<<#x<<"="<<x<<endl 10 inline int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 14 }inline void write(int x,char opt='\n'){ 15 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 16 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 17 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 18 }using namespace AE86; 19 const int NN=105; 20 int n,m,f[NN][1<<8],g[NN][10]; 21 vector<int> sta[NN]; 22 vector<int> pre; 23 inline void printsta(int x){ 24 if(!x) {puts("0");return;} 25 pre.clear(); 26 while(x)pre.push_back(x&1),x>>=1; 27 for(int i=0;i<pre.size();i++) printf("%d",pre[i]); 28 for(int i=m;i>pre.size();i--) printf("0"); 29 puts(""); 30 } 31 inline void get_sta(){ 32 sta[0].push_back(0); 33 for(int i=1;i<=n;i++){ 34 for(int j=0;j<(1<<m);j++){ 35 bool flag=true; 36 for(int k=1;flag&&k<=m;k++){ 37 if(g[i][k]&&!g[i][k-1]&&!(j&(1<<k-1)))flag=false; 38 if(!g[i][k]&&(j&(1<<k-1)))flag=false; 39 } 40 if(flag) sta[i].push_back(j); 41 } 42 } 43 } 44 bool pw[10][10]; 45 inline void prework(int now,int s){ 46 memset(pw,0,sizeof(pw)); 47 for(int mx,i=1;i<=m;i++)if(s&(1<<i-1)){ 48 mx=1;for(int j=i+1;j<=m;j++) 49 if(!(s&(1<<j-1))&&g[now][j])++mx; 50 else break; 51 pw[i][mx]=1; 52 } 53 } 54 inline int calc(int to,int s,int ans=0){ 55 int last=0; 56 for(int i=1;i<=m;i++){ 57 if(s&(1<<i-1)){ 58 if(last&&!pw[last][i-last])++ans; 59 last=i; 60 } 61 if(!g[to][i]&&last){ 62 if(!pw[last][i-last])++ans; 63 last=0; 64 } 65 } 66 if(last&&!pw[last][m-last+1])++ans; 67 return ans; 68 } 69 inline void cmin(int &a,int b){a<b?(a=a):(a=b);} 70 namespace WSN{ 71 inline short main(){ 72 freopen("merging.in","r",stdin); 73 freopen("merging.out","w",stdout); 74 n=read(); m=read(); memset(f,0x3f,sizeof(f)); f[0][0]=0; 75 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) g[i][j]=read(); 76 // cout<<calc(1,2,149,173)<<endl; 77 get_sta(); 78 // for(int i=1;i<=n;i++){ 79 // printf("level=%d:\n",i); 80 // for(int j=0;j<sta[i].size();j++){ 81 // printsta(sta[i][j]); 82 // } 83 // } 84 for(int i=0;i<n;i++){ int to=i+1; 85 for(int j=0;j<sta[i].size();j++){ 86 if(f[i][sta[i][j]]>1e9)continue; 87 prework(i,sta[i][j]); 88 for(int k=0;k<sta[to].size();k++){ 89 int tmp=calc(to,sta[to][k]); 90 cmin(f[to][sta[to][k]],f[i][sta[i][j]]+tmp); 91 } 92 } 93 } 94 int ans=0x3fffffff; 95 for(int i=0;i<sta[n].size();i++) ans=min(ans,f[n][sta[n][i]]); 96 write(ans); 97 return 0; 98 } 99 } 100 signed main(){return WSN::main();}
T2 光线追踪
考场上码了一年的珂朵莉树全$RE$了,指针就像女朋友,动不动就把我放弃了。。。。然后就被杀死了
想到了几乎全部思路,但是不会实现,因为是浮点数,细节过于之多了
每个矩形显然只有靠左下的一条竖线和横线来挡光,分别开线段树维护,更新哪些角度会经过他
只搞询问的哪些角度就行,(要不然没法维护),离散化一下就直接维护了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define int long long 6 using namespace std; 7 namespace AE86{ 8 #define fuck cout<<"fuck"<<endl 9 #define out(x) cout<<#x<<"="<<x<<endl 10 inline int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 14 }inline void write(int x,char opt='\n'){ 15 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 16 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 17 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 18 }using namespace AE86; 19 typedef long double D; 20 const int NN=1e5+5,inf=1e9+7; 21 int q,cnt; 22 D sl[NN<<2]; 23 struct query{int opt,x,y,xx,yy;}a[NN]; 24 inline int jud(int x){return x>=1000000000?0:x;} 25 struct segment{int id,xy;}; 26 inline segment Min(segment a,segment b){return a.xy<b.xy?a:(a.xy==b.xy?(a.id<b.id?b:a):b);} 27 struct SNOWtree{ 28 #define lid (id<<1) 29 #define rid (id<<1|1) 30 int ll[NN<<4],rr[NN<<4]; 31 segment mn[NN<<4]; 32 inline void build(int id,int l,int r){ 33 ll[id]=l;rr[id]=r;mn[id]=segment{inf,inf};if(l==r)return; 34 int mid=l+r>>1;build(lid,l,mid);build(rid,mid+1,r); 35 } 36 inline void update(int id,int l,int r,segment val){ 37 if(l<=ll[id]&&rr[id]<=r)return mn[id]=Min(mn[id],val),void(); 38 if(l<=rr[lid]) update(lid,l,r,val);if(r>=ll[rid]) update(rid,l,r,val); 39 } 40 inline segment query(int id,int pos){ 41 if(ll[id]==rr[id])return mn[id]; 42 return Min(mn[id],pos<=rr[lid]?query(lid,pos):query(rid,pos)); 43 } 44 }X,Y; 45 // #define mzs 46 #define wsn 47 namespace WSN{ 48 inline short main(){ 49 #ifdef mzs 50 freopen("in.in","r",stdin); 51 #endif 52 #ifdef wsn 53 freopen("raytracing.in","r",stdin); 54 freopen("raytracing.out","w",stdout); 55 #endif 56 q=read(); 57 for(int i=1;i<=q;i++){ 58 a[i].opt=read(); 59 if(a[i].opt==1){ 60 a[i].x=read();a[i].y=read();a[i].xx=read();a[i].yy=read(); 61 if(a[i].x){ 62 sl[++cnt]=1.0L*a[i].y/a[i].x; 63 sl[++cnt]=1.0L*a[i].yy/a[i].x; 64 sl[++cnt]=1.0L*a[i].y/a[i].x; 65 }else{ 66 sl[++cnt]=1.0L*a[i].y/1e-7L; 67 sl[++cnt]=1.0L*a[i].yy/1e-7L; 68 sl[++cnt]=1.0L*a[i].y/a[i].x; 69 } 70 }else{ 71 a[i].x=read();a[i].y=read(); 72 if(a[i].x) sl[++cnt]=1.0L*a[i].y/a[i].x; 73 } 74 } 75 sort(sl+1,sl+cnt+1); cnt=unique(sl+1,sl+cnt+1)-sl-1; 76 X.build(1,1,cnt); Y.build(1,1,cnt); 77 int mnx=inf,mny=inf,mnxx,mnyy; 78 for(int i=1;i<=q;i++) 79 if(a[i].opt==1){ 80 if(!a[i].x) if(mnx>=a[i].y) mnx=a[i].y,mnxx=i; 81 if(!a[i].y) if(mny>=a[i].x) mny=a[i].x,mnyy=i; 82 int x1=lower_bound(sl+1,sl+cnt+1,1.0L*a[i].y/(a[i].x?a[i].x:1e-7L))-sl; 83 int x2=lower_bound(sl+1,sl+cnt+1,1.0L*a[i].yy/(a[i].x?a[i].x:1e-7L))-sl; 84 int x3=lower_bound(sl+1,sl+cnt+1,1.0L*a[i].y/a[i].xx)-sl; 85 X.update(1,x1,x2,segment{i,a[i].x}); 86 Y.update(1,x3,x1,segment{i,a[i].y}); 87 }else{ 88 if(!a[i].x){write(mnxx);continue;} 89 if(!a[i].y){write(mnyy);continue;} 90 segment x=X.query(1,lower_bound(sl+1,sl+cnt+1,1.0L*a[i].y/a[i].x)-sl); 91 segment y=Y.query(1,lower_bound(sl+1,sl+cnt+1,1.0L*a[i].y/a[i].x)-sl); 92 if(x.xy*a[i].y==y.xy*a[i].x)write(jud(max(x.id,y.id))); 93 else if(x.xy*a[i].y<y.xy*a[i].x)write(jud(x.id)); 94 else write(jud(y.id)); 95 } 96 return 0; 97 } 98 } 99 signed main(){return WSN::main();}
T3 百鸽笼
$UNR#3Day2$的题
记录当前你要求的那一列为$x$,现在你要算他的概率
我们要知道让所有其他列都在他之前填满的方案数
不妨使用容斥,考虑集合$S$表示在他之后被填满的都有哪几列
显然这些情况都是不合法的,我们加加减减就可以求出来合法的答案。。。
关于容斥系数问题我们待会再说,先考虑别的
发现我们知道这个集合里面真正有哪几列是没必要的,只知道$|S|$就可以了
所以这时就可以用背包统计方案数了,设$dp[i][j]$表示有$i$列,总共填了$j$个人的方案
然后转移的时候要保证只有你算的那列要放满,其他的都不能放满,所以枚举容量的时候只能枚举到$a[i]-1$
那么$f[i+1][j+c]=f[i][j]\times C_{j+c}^{c}$
然后把你要算的那个$x$列的$a[x]-1$个数随机插到原来的可能的序列里面,也就是再乘上一个组合数
少插一个是为了保证有一个在序列的末尾(这里的序列是说假设有$N$个鸽子,每次鸽子选择进入的列生成的序列,那么所有不同序列的最后一个数就是要统计的当前的答案)
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #define int long long 7 using namespace std; 8 namespace AE86{ 9 #define fuck cout<<"fuck"<<endl 10 #define out(x) cout<<#x<<"="<<x<<endl 11 inline int read(){ 12 int x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 15 }inline void write(int x,char opt='\n'){ 16 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 17 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 18 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 19 }using namespace AE86; 20 const int mod=998244353,NN=50; 21 int n,a[NN],N,ans; 22 int C[2001][2001],f[NN][NN*NN]; 23 inline int qmo(int a,int b,int ans=1){ 24 int c=mod;for(;b;b>>=1,a=a*a%c)if(b&1)ans=ans*a%c; 25 return ans; 26 }inline int inv(int x){return qmo(x,mod-2);} 27 inline void prework(int n=2000){ 28 C[0][0]=1;for(int i=1;i<=n;i++){C[i][0]=C[i][i]=1; 29 for(int j=1;j<i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; 30 } 31 } 32 inline int getans(int x,int ans=0){ 33 memset(f,0,sizeof(f)); f[0][0]=1; int sum=0; ans=1; 34 for(int i=1;i<=n;i++) if(i!=x){ 35 for(int j=i;~j;j--)for(int k=sum;~k;k--)if(f[j][k]){ 36 int tmp=f[j][k]; 37 for(int l=0;l<a[i];l++) 38 f[j+1][k+l]=(f[j+1][k+l]+tmp*C[k+l][l]%mod)%mod; 39 } 40 sum+=a[i]-1; 41 } 42 for(int i=1;i<n;i++)for(int k=0;k<=sum;k++){ 43 int tmp=qmo(i+1,k+a[x]),flag=(i&1)?-1:1; 44 ans=(ans+flag*f[i][k]*C[k+a[x]-1][a[x]-1]%mod*inv(tmp)%mod)%mod; 45 } 46 return (ans+mod)%mod; 47 } 48 namespace WSN{ 49 inline short main(){ 50 freopen("c.in","r",stdin);freopen("c.out","w",stdout); 51 n=read(); prework(); for(int i=1;i<=n;i++)a[i]=read(); 52 for(int i=1;i<=n;i++)write(getans(i),' '); puts(""); 53 return 0; 54 } 55 } 56 signed main(){return WSN::main();}
T4 滑稽树下你和我
预处理点和点间的距离,点和边之间的距离,然后把每个边当成点和他的两个端点连边,跑最长路即可
1 #include<cmath> 2 #include<queue> 3 #include<cstdio> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 using namespace std; 8 namespace AE86{ 9 #define fuck cout<<"fuck"<<endl 10 #define out(x) cout<<#x<<"="<<x<<endl 11 inline int read(){ 12 int x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 15 }inline void write(int x,char opt='\n'){ 16 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 17 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 18 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 19 }using namespace AE86; 20 typedef double D; 21 const int NN=2005; 22 int n,stx,sty,cnt,deg[NN]; 23 D dis[NN][NN],dit[NN][NN]; 24 struct SNOW{int fr,to,next;}e[NN*NN];int head[NN],rp; 25 inline void add(int x,int y){ 26 e[++rp]=SNOW{x,y,head[x]};head[x]=rp; 27 e[++rp]=SNOW{y,x,head[y]};head[y]=rp; 28 } 29 struct point{ 30 D x,y; 31 bool operator==(const point&a)const{return (x==a.x)&&(y==a.y);} 32 D operator-(const point&a)const{return (y-a.y)/(x-a.x);} 33 D operator*(const point&a)const{return sqrt(pow(x-a.x,2.0)+pow(y-a.y,2.0));} 34 };point p[NN]; 35 struct line{ 36 D k,b;point a1,a2; 37 point operator*(const line&ret)const{D x=(b-ret.b)/(ret.k-k);return point{x,k*x+b};} 38 };line l[NN]; 39 struct node{ 40 int x,y; D data; 41 friend bool operator<(node a,node b){ 42 return a.data>b.data; 43 } 44 };priority_queue<node> Q; 45 bool vis[NN][NN]; 46 inline void dijktra(){ 47 for(int i=1;i<=cnt+10;++i)for(int j=1;j<=cnt+10;++j)dit[i][j]=1e9; 48 dit[stx][sty]=dis[stx][sty]; 49 Q.push(node{stx,sty,dit[stx][sty]}); 50 while(!Q.empty()){ 51 node now=Q.top(); Q.pop(); 52 if(vis[now.x][now.y])continue; 53 vis[now.x][now.y]=1; 54 for(int i=head[now.x];i;i=e[i].next){ 55 int v=e[i].to; 56 if(dit[v][now.y]>max(dit[now.x][now.y],dis[v][now.y])){ 57 dit[v][now.y]=max(dit[now.x][now.y],dis[v][now.y]); 58 Q.push(node{v,now.y,dit[v][now.y]}); 59 } 60 } 61 for(int i=head[now.y];i;i=e[i].next){ 62 int v=e[i].to; 63 if(dit[now.x][v]>max(dit[now.x][now.y],dis[now.x][v])){ 64 dit[now.x][v]=max(dit[now.x][now.y],dis[now.x][v]); 65 Q.push(node{now.x,v,dit[now.x][v]}); 66 } 67 } 68 } 69 } 70 namespace WSN{ 71 inline short main(){ 72 freopen("tree.in","r",stdin); 73 freopen("tree.out","w",stdout); 74 cnt=n=read();stx=read();sty=read(); 75 for(int i=1;i<=n;++i){ 76 int x=read(),y=read(); 77 p[i]=point{1.0*x,1.0*y}; 78 } 79 for(int i=1;i<n;++i){ 80 int u=read(),v=read(); ++cnt; ++deg[u]; ++deg[v]; 81 D k=p[u]-p[v],b=p[u].y-k*p[u].x; 82 l[i]=line{k,b,p[u],p[v]}; 83 add(u,cnt); add(cnt,v); 84 } 85 for(int i=1;i<=n;++i){ 86 for(int j=1;j<=n;++j) dis[i][j]=dis[j][i]=p[i]*p[j]; 87 for(int j=1;j<n;++j){ 88 D k=-1.0/l[j].k,b=p[i].y-p[i].x*k; 89 line c=line{k,b};point d=c*l[j]; 90 if((l[j].a1.x<=d.x&&d.x<=l[j].a2.x)||(l[j].a2.x<=d.x&&d.x<=l[j].a1.x)) dis[i][j+n]=d*p[i]; 91 else dis[i][j+n]=min(l[j].a1*p[i],l[j].a2*p[i]); 92 dis[j+n][i]=dis[i][j+n]; 93 } 94 } 95 dijktra();D ans=1e9; 96 for(int i=1;i<=n;++i)if(deg[i]==1) 97 for(int j=1;j<=n;++j)if(deg[j]==1) 98 ans=min(ans,dit[i][j]); 99 printf("%.10lf\n",ans); 100 return 0; 101 } 102 } 103 signed main(){return WSN::main();}