1. 程式人生 > 其它 >Noip模擬80 2021.10.18

Noip模擬80 2021.10.18

T1 鄰面合併 T2 光線追蹤 T3 百鴿籠 T4 滑稽樹下你和我

預計得分: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