Loading

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();}
大雾60

正解必然是状压冻龟

设$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();}
View Code

 

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();}
View Code

 

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();}
View Code

 

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();}
View Code

 

posted @ 2021-10-19 19:30  雪域亡魂  阅读(93)  评论(0编辑  收藏  举报