2017/7/27 考试吐槽
2017 07 27 分数:152
一句话:我菜爆了……
A、玛雅游戏
吐槽时间:这是要每天一道爆搜的节奏吗……太长不打
题解:爆搜!爆搜!爆搜!没啥说的!
(话说回来这函数真恶心……又长又乱……大不了NOIP爆搜100分不要了)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #define R register 7 using namespace std; 8 int map[6][8],n,num[6],backup[6][6][8]; 9 vector<int>row,col,dire; 10 inline void Fall() 11 { 12 for(R int i=1;i<=5;++i) 13 { 14 int val=0; 15 for(R int j=1;j<=7;++j) 16 if(map[i][j]&&val)swap(map[i][j-val],map[i][j]); 17 else if(!map[i][j])val++; 18 } 19 } 20 bool t,clear[6][8]; 21 inline void Wipe() 22 { 23 memset(clear,0,sizeof(clear)); 24 for(R int i=1;i<=5;++i) 25 for(R int j=1;j<=7;++j) 26 if(map[i][j]) 27 { 28 int cnt=0; 29 for(R int k=i;k<=5&&map[k][j]==map[i][j];++k)cnt++; 30 if(cnt>=3) 31 { 32 t=1; 33 for(R int k=i;k<i+cnt;++ k)clear[k][j]=1; 34 } 35 cnt=0; 36 for(R int k=j;k<=7&&map[i][k]==map[i][j];++k)cnt++; 37 if(cnt>=3) 38 { 39 t=1; 40 for(R int k=j;k<j+cnt;++k)clear[i][k]=1; 41 } 42 } 43 for(R int i=1;i<=5;++i) 44 for(R int j=1;j<=7;++j) 45 if(clear[i][j])map[i][j]=0; 46 } 47 inline void Move(int ro,int co,int dir) 48 { 49 swap(map[ro+dir][co],map[ro][co]);Fall(); 50 t=0; 51 do 52 { 53 t=0; 54 Wipe(); 55 Fall(); 56 }while(t); 57 } 58 inline void dfs(int step) 59 { 60 if(step>n)return; 61 if(step==n) 62 { 63 bool t=1; 64 for(R int i=1;i<=5;++i) 65 for(R int j=1;j<=7;++j) 66 if(map[i][j]) 67 { 68 t=0; 69 return; 70 } 71 if(t) 72 { 73 for(R int i=0;i<row.size();++i)printf("%d %d %d\n",row[i],col[i],dire[i]); 74 //while(1); 75 exit(0); 76 } 77 return; 78 } 79 memcpy(backup[step],map,sizeof(map)); 80 for(R int i=1;i<=5;++i) 81 for(R int j=1;j<=7&&map[i][j];++j) 82 { 83 if(i<5&&map[i+1][j]!=map[i][j]) 84 { 85 row.push_back(i-1); 86 col.push_back(j-1); 87 dire.push_back(1); 88 Move(i,j,1); 89 dfs(step+1); 90 memcpy(map,backup[step],sizeof(map)); 91 row.erase(row.begin()+step); 92 col.erase(col.begin()+step); 93 dire.erase(dire.begin()+step); 94 } 95 if(i>1&&map[i-1][j]==0&&map[i-1][j]!=map[i][j])//卧槽还有这种操作…… 96 { 97 row.push_back(i-1); 98 col.push_back(j-1); 99 dire.push_back(-1); 100 Move(i,j,-1); 101 dfs(step+1); 102 memcpy(map,backup[step],sizeof(map)); 103 row.erase(row.begin()+step); 104 col.erase(col.begin()+step); 105 dire.erase(dire.begin()+step); 106 } 107 } 108 return; 109 } 110 int haha() 111 { 112 freopen("mayan.in","r",stdin); 113 freopen("mayan.out","w",stdout); 114 scanf("%d",&n); 115 for(R int i=1;i<=5;++i) 116 { 117 int x; 118 while(scanf("%d",&x)!=EOF&&x) 119 map[i][++num[i]]=x; 120 } 121 dfs(0); 122 puts("-1"); 123 //while(1); 124 } 125 int sb=haha(); 126 int main(){;}
B、Monotonicity 2
吐槽时间:你们这样做让我这个dp不会数据结构也不会的蒟蒻瑟瑟发抖……
题解:我们可以观察到状态转移方程为$f[i]=max{f[j]|j<i且符号满足条件}$,等号右边是一个最大化的式子,很明显可以用数据结构优化。我用了两棵线段树分别维护大于号小于号情况(实际是太蒻了分不清大小),神犇mk使用了两个树状数组卡常大成功,ORZ!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=500005; 7 int a[maxn],n,f[maxn],k,ans; 8 char s[maxn]; 9 int q[maxn<<1],q1[maxn<<4],q2[maxn<<4],line[maxn]; 10 void Update(int pos,int val) 11 { 12 q[pos]=max(val,q[pos]); 13 } 14 int Query(int pos) 15 { 16 return q[pos]; 17 } 18 #define mid ((l+r)>>1) 19 #define lc root<<1 20 #define rc root<<1|1 21 #define lson lc,l,mid 22 #define rson rc,mid+1,r 23 void Update1(int root,int l,int r,int pos,int val) 24 { 25 if(l==r) 26 { 27 q1[root]=max(q1[root],val); 28 return; 29 } 30 if(pos<=mid)Update1(lson,pos,val); 31 else Update1(rson,pos,val); 32 q1[root]=max(q1[lc],q1[rc]); 33 } 34 int Query1(int root,int l,int r,int L,int R) 35 { 36 if(L<=l&&r<=R)return q1[root]; 37 if(R<=mid)return Query1(lson,L,R); 38 else if(L>mid)return Query1(rson,L,R); 39 return max(Query1(lson,L,R),Query1(rson,L,R)); 40 } 41 void Update2(int root,int l,int r,int pos,int val) 42 { 43 if(l==r) 44 { 45 q2[root]=max(q2[root],val); 46 return; 47 } 48 if(pos<=mid)Update2(lson,pos,val); 49 else Update2(rson,pos,val); 50 q2[root]=max(q2[lc],q2[rc]); 51 } 52 int Query2(int root,int l,int r,int L,int R) 53 { 54 if(L<=l&&r<=R)return q2[root]; 55 if(R<=mid)return Query2(lson,L,R); 56 else if(L>mid)return Query2(rson,L,R); 57 return max(Query2(lson,L,R),Query2(rson,L,R)); 58 } 59 void Add(int pos,int val) 60 { 61 if(s[line[val]]=='=')Update(pos,val); 62 else if(s[line[val]]=='<')Update1(1,0,1000001,pos,val); 63 else Update2(1,0,1000001,pos,val); 64 } 65 int haha() 66 { 67 freopen("mot.in","r",stdin); 68 freopen("mot.out","w",stdout); 69 scanf("%d%d",&n,&k); 70 for(int i=1;i<=n;i++) 71 { 72 scanf("%d",&a[i]); 73 line[i]=(i-1)%k+1; 74 } 75 for(int i=1;i<=k;i++) 76 { 77 char c=getchar(); 78 while(c!='<'&&c!='>'&&c!='=')c=getchar(); 79 s[i]=c; 80 } 81 f[1]=1;Add(a[1],1); 82 int ans=1; 83 for(int i=2;i<=n;i++) 84 { 85 int res=Query(a[i]),res1=Query1(1,0,1000001,0,a[i]-1),res2=Query2(1,0,1000001,a[i]+1,1000001); 86 Add(a[i],res+1);Add(a[i],res1+1);Add(a[i],res2+1); 87 f[i]=max(res,max(res1,res2))+1; 88 ans=max(ans,f[i]); 89 } 90 printf("%d\n",ans); 91 //while(1); 92 } 93 int sb=haha(); 94 int main(){;}
C、杀人游戏
吐槽:又一道对打挂正解不友好题目……利益相关:少考虑两种(假的)特殊情况炸飞72分(稍后介绍坑点)
题解:首先我们可以想到,如果出现了一个环,这个环只会让警察冒一次险。其次,两个联通的环,警察也只需冒一次险。那么我们就可以Tarjan缩点,完成后扫一遍入度为0的点即为所求(然而wxh神犇没缩点拿下全场最高分)。
特别注意:如果一个强连通分量,里面只有一个点,这个点入度出度都为零或者它连接的点入度均不为一,我们就可以不查他,个数就要减1(炸飞72分的怨念)。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<vector> 6 using namespace std; 7 const int maxn=100005,maxm=300005; 8 struct node 9 { 10 int from,to,next; 11 }edge[maxm<<1]; 12 int head[maxn],tot,entrance_degree[maxn],exit_degree[maxn],size[maxn]; 13 int n,m; 14 void addedge(int u,int v) 15 { 16 edge[++tot]=(node){u,v,head[u]};head[u]=tot; 17 } 18 int low[maxn],dfn[maxn],cnt,scnt,belong[maxn]; 19 #include<stack> 20 stack<int>s; 21 void dfs1(int pos) 22 { 23 low[pos]=dfn[pos]=++cnt; 24 s.push(pos); 25 for(int i=head[pos];i;i=edge[i].next) 26 { 27 int v=edge[i].to; 28 if(!dfn[v]) 29 { 30 dfs1(v); 31 low[pos]=min(low[v],low[pos]); 32 } 33 else if(!belong[v])low[pos]=min(low[pos],dfn[v]); 34 } 35 if(low[pos]==dfn[pos]) 36 { 37 scnt++;int k; 38 do 39 { 40 k=s.top();s.pop(); 41 belong[k]=scnt; 42 size[scnt]++; 43 }while(k!=pos); 44 } 45 } 46 bool vis[maxn]; 47 int ans; 48 void dfs2(int from) 49 { 50 bool t=1; 51 if(!exit_degree[from])t=0; 52 for(int i=head[from];i;i=edge[i].next) 53 { 54 int v=edge[i].to; 55 if(entrance_degree[v]==1)t=0; 56 dfs2(v); 57 } 58 vis[from]=t; 59 } 60 int haha() 61 { 62 freopen("killer.in","r",stdin); 63 freopen("killer.out","w",stdout); 64 scanf("%d%d",&n,&m); 65 for(int i=1;i<=m;i++) 66 { 67 int x,y;scanf("%d%d",&x,&y); 68 addedge(x,y); 69 } 70 for(int i=1;i<=n;i++) 71 if(!dfn[i])dfs1(i); 72 memset(head,0,sizeof(head)); 73 for(int i=1;i<=m;i++) 74 { 75 int u=edge[i].from,v=edge[i].to; 76 u=belong[u],v=belong[v]; 77 if(u!=v) 78 { 79 addedge(u,v); 80 exit_degree[u]++; 81 entrance_degree[v]++; 82 } 83 } 84 ans=0; 85 for(int i=1;i<=scnt;i++) 86 if(!entrance_degree[i]) 87 { 88 ans++; 89 dfs2(i); 90 } 91 for(int i=1;i<=scnt;i++) 92 if((vis[i]||(!entrance_degree[i]&&!exit_degree[i]))&&size[i]==1)//俩特殊情况挂飞72分……想死…… 93 { 94 ans--; 95 break; 96 } 97 printf("%0.6lf\n",1.0-(ans*1.0)/(n*1.0)); 98 } 99 int sb=haha(); 100 int main(){;}
D、弱题
吐槽:果然弱题,对迭代这么友好……
题解:暴力推式子可以得到$f[x][now]=f[x][last]-f[x][last]/m+f[x-1][last]/m$,k极大,天然的矩阵优化(然而你考试不一样是迭代加精度优化),但是注意到n<=1000,矩阵快速幂绝对炸飞(还没我分高),于是我们采用奇技淫巧:
(原图错了凑合看吧)
可以看到,每一行都相当于上一行向右平移得到的,于是我们只维护第一行,随后递推出下面几行就行了。
(改题这么富裕的时间都能把double打成int,AFO得了,世界再见)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int maxn=1005; 8 const double eps=1e-8; 9 int m,n,k; 10 struct Matrix 11 { 12 double a[1005][1005]; 13 }Ans,x; 14 double tmp[maxn];//……写成int……我还能说点啥……世界再见…… 15 __attribute__((optimize("O3")))void qpow(Matrix p,int tim) 16 { 17 for(;tim;tim>>=1) 18 { 19 if(tim&1) 20 { 21 for(int i=1;i<=n;i++)tmp[i]=0; 22 for(int i=1;i<=n;i++) 23 for(int j=1;j<=n;j++)tmp[i]+=x.a[1][j]*Ans.a[j][i]; 24 for(int i=1;i<=n;i++)x.a[1][i]=tmp[i]; 25 } 26 for(int i=1;i<=n;i++)tmp[i]=0; 27 for(int i=1;i<=n;i++) 28 for(int j=1;j<=n;j++)tmp[i]+=Ans.a[1][j]*Ans.a[j][i]; 29 for(int i=1;i<=n;i++)Ans.a[1][i]=tmp[i]; 30 for(int i=2;i<=n;i++) 31 for(int j=1;j<=n;j++) 32 if(j==1)Ans.a[i][j]=Ans.a[i-1][n]; 33 else Ans.a[i][j]=Ans.a[i-1][j-1]; 34 } 35 } 36 __attribute__((optimize("O3")))int haha() 37 { 38 //freopen("data.in","r",stdin); 39 //freopen("data.out","w",stdout); 40 scanf("%d%d%d",&n,&m,&k); 41 for(int i=1;i<=n;i++)scanf("%lf",&x.a[1][i]); 42 double p1=1.0-(1.0/(m*1.0)),p2=1.0/(m*1.0); 43 for(int i=1;i<=n;i++) 44 if(i==n) 45 { 46 Ans.a[n][n]=p1; 47 Ans.a[n][1]=p2; 48 } 49 else 50 { 51 Ans.a[i][i]=p1; 52 Ans.a[i][i+1]=p2; 53 } 54 qpow(Ans,k); 55 for(int i=1;i<=n;i++)printf("%0.3lf\n",x.a[1][i]); 56 } 57 int sb=haha(); 58 __attribute__((optimize("O3")))int main(){;}
(不要在意那个O3……那不是重点……)
只要是活着的东西,就算是神我也杀给你看。