传送门:https://ac.nowcoder.com/acm/contest/12606#question
A题 Weird Flecks, But OK
题解:计算几何 最小圆覆盖问题
B题 Code Names
题解:建图+匈牙利算法 最大团=补图的最大独立集 最大独立集=点数-最大匹配/2
C题 New Maths
题解:搜索
D Some Sum
题解:签到题 暴力
E Early Orders
题解:栈模拟
F Pulling Their Weight
题解:签到题
G Birthday Paradox
题解:组合数学
H On Average They're Purple
题解:最短路
J This Ain't Your Grandpa's Checkerboard
题解:模拟
A把点投到三个平面,做三次最小点覆盖。

#include<bits/stdc++.h> using namespace std; #define N 5210 #define pf(x) ((x)*(x)) #define eps 1e-6 int n; double x[N],y[N],z[N]; double R; struct point { double x,y; }p[N],O; //求两点间的距离 double getdis(point a,point b) { return sqrt(pf(a.x-b.x)+pf(a.y-b.y)); } //三点定一圆的圆心 point getO(point p1,point p2,point p3) { point res; double a=p2.x-p1.x; double b=p2.y-p1.y; double c=p3.x-p2.x; double d=p3.y-p2.y; double e=pf(p2.x)+pf(p2.y)-pf(p1.x)-pf(p1.y); double f=pf(p3.x)+pf(p3.y)-pf(p2.x)-pf(p2.y); res.x=(f*b-e*d)/(c*b-a*d)/2.0; res.y=(a*f-e*c)/(a*d-b*c)/2.0; return res; } void slove() { O=p[1];R=0; for(int i=1;i<=n;i++) { if(getdis(p[i],O)-R>eps) { O=p[i];R=0; for(int j=1;j<i;j++) { if(getdis(p[j],O)-R>eps) { O=(point){(p[i].x+p[j].x)/2.0,(p[i].y+p[j].y)/2.0}; R=getdis(p[i],p[j])/2.0; for(int k=1;k<j;k++) { if(getdis(p[k],O)-R>eps) { O=getO(p[i],p[j],p[k]); R=getdis(p[i],O); } } } } } } } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>x[i]>>y[i]>>z[i]; double ans=100000; for(int i=1;i<=n;i++) p[i].x=x[i],p[i].y=y[i]; random_shuffle(p+1,p+1+n); slove(); if(ans-R>eps) ans=R; for(int i=1;i<=n;i++) p[i].x=x[i],p[i].y=z[i]; random_shuffle(p+1,p+1+n); slove(); if(ans-R>eps) ans=R; for(int i=1;i<=n;i++) p[i].x=y[i],p[i].y=z[i]; random_shuffle(p+1,p+1+n); slove(); if(ans-R>eps) ans=R; printf("%.10f",2*ans); }
B
将不能通过一次交换就变成对方的字符串连线,发现答案是最大完全子图
建立上图的补图,即 将能通过交换就变成对方的字符串连线建图,求最大匹配数。
最大完全子图=补图的最大独立集=点数-最大匹配/2

#include<iostream> #include<cstdio> #include<cstring> #define maxn 1000001 using namespace std; int n,sumedge,cnt; int head[maxn],vis[maxn],match[maxn]; string s[maxn]; struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[maxn<<1]; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } bool pipei(int x){ for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(vis[v]==0){ vis[v]=1; if(!match[v]||pipei(match[v])){ match[v]=x;return true; } } }return false; } void INit() { scanf("%d",&n); int len; for(int i=1;i<=n;i++) cin>>s[i]; len=s[1].length(); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { int js=0; for(int k=0;k<len;k++) { if(s[i][k]!=s[j][k]) js++; } if(js<3) { add(i,j); add(j,i); // cout<<i<<"--"<<j<<endl; } } } } int main() { INit(); int ans=0; for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(pipei(i)) ans++; } cout<<n-ans/2; return 0; }
C
搜索 枚举a的每一位

#include<bits/stdc++.h> using namespace std; #define N 55 int len; int a[N]; char s[N]; bool flag; void dfs(int now) { if(now>len&&!flag) { int gg=(len+1)/2; flag=1; for(int i=1;i<=gg;i++) { cout<<a[i]; } return ; } for(int i=0;i<=9;i++) { a[now]=i; int sum=0; for(int j=1;j<=now;j++) { sum=sum+a[j]*a[now-j+1]; } if(sum%10==s[now]-'0') dfs(now+1); } } int main() { scanf("%s",s+1); len=strlen(s+1); if(len%2==0) { cout<<"-1 "; return 0; } dfs(1); if(!flag) { cout<<"-1"; } return 0; }
D
略

#include<bits/stdc++.h> using namespace std; int main() { int n; cin>>n; bool ou=0,ji=0; for(int i=1;i<=100;i++) { int sum=0; for(int j=i;j<=i+n-1;j++) { sum=sum+j; } if(sum%2==0)ou=1; if(sum%2==1)ji=1; } if(ou==1&&ji==1) cout<<"Either"; if(ou==1&&ji==0) cout<<"Even"; if(ou==0&&ji==1) cout<<"Odd"; return 0; } /* */
E
维护一个栈
1)当前数在栈中,不做操作
2)当前数不在栈中时
若当前数比栈顶小,且栈顶的数在后面还会再出现,栈顶的数出栈,当前数进栈
代码队友写的

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<stack> using namespace std; int s[200050]={0}; int flag[200050]={0}; stack<int>st; int vis[200050]={0}; int ans[200050]={0}; int main() { int n,k; cin>>n>>k; int i; for(i=0;i<n;i++) { cin>>s[i]; } int len=n; for(int i=0;i<len;i++) { flag[s[i]]++;//计算数量 } st.push(s[0]); vis[s[0]]=1;//标记 flag[s[0]]--; for(int i=1;i<len;i++) { flag[s[i]]--; if(vis[s[i]])//在栈内,就不用操作,直接下一个元素 continue; while(!st.empty()&&st.top()>s[i]&&flag[st.top()]>0)//s[i]比栈顶元素小且后面还有栈顶元素,则出栈 { vis[st.top()]=0; st.pop(); } st.push(s[i]);//没有标记的进栈 vis[s[i]]=1; } int sum=0; while(!st.empty()) { if(ans[sum]!=st.top()) { ans[sum++]=st.top(); } st.pop(); } for(int i=sum-1;i>=0;i--)//倒序输出 { if(ans[i]!=ans[i+1]) { cout<<ans[i]<<' '; } } }
F
略 队友代码

#include<iostream> using namespace std; long long n,i,x,sum1=0,sum2=0,a[20005],t,u; int main() {cin.tie(0);ios::sync_with_stdio(false); cin>>n; for(i=1;i<=n;i++) { cin>>x; sum1+=x; a[x]++; } for(i=1;i<=20000;i++) { if(a[i]>0) { if(a[i]%2==0) {t=sum2+a[i]/2*i;if(t*2==sum1) {cout<<i<<endl;return 0;}} else { t=sum2; u=sum1-sum2-a[i]*i; if(t==u){cout<<i<<endl;return 0;} } }else { t=sum2; if(t*2==sum1) {cout<<i<<endl;return 0;} } sum2+=a[i]*i; } return 0; }
G
把上面式子拆开算就行

#include<bits/stdc++.h> using namespace std; #define N 520 int n,m; double Log[100000]; int d[N],c[N]; double ans; double log10(int x) { return log(x)/log(10); } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n; for(int i=1;i<100000;i++) Log[i]=Log[i]+Log[i-1]+log10(i); for(int i=1;i<=n;i++) cin>>c[i],d[c[i]]++,m+=c[i]; ans=Log[365]-Log[365-n]-Log[n]+Log[m]+Log[n]-m*log10(365); for(int i=1;i<=n;i++) ans=ans-Log[c[i]]; for(int i=1;i<=100;i++) ans=ans-Log[d[i]]; printf("%.15lf",ans); return 0; }
H
发现最小颜色改变次数为 1到n的最短路径长度-1
求最短路用的优化后的狄杰斯特拉

#include<iostream> #include<cstdio> #include<queue> #include<cstring> #define N 100008 using namespace std; int n,m,s; int sumedge; int head[N],dis[N],vis[N]; struct Edge{ int x,y,z,nxt; Edge(int x=0,int y=0,int z=0,int nxt=0): x(x),y(y),z(z),nxt(nxt){} }edge[N*2]; struct node{ int x,dis; bool operator < (node a) const{ return dis>a.dis; } }; priority_queue<node>q; void add(int x,int y,int z){ edge[++sumedge]=Edge(x,y,z,head[x]); head[x]=sumedge; } void dijikstra(int x){ while(!q.empty())q.pop(); memset(dis,0x3f,sizeof(dis)); dis[x]=0; q.push((node){x,0}); while(!q.empty()){ node now=q.top();q.pop(); if(vis[now.x])continue; vis[now.x]=true; for(int i=head[now.x];i;i=edge[i].nxt){ int v=edge[i].y; if(dis[v]>dis[now.x]+edge[i].z){ dis[v]=dis[now.x]+edge[i].z; q.push((node){v,dis[v]}); } } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y,1); add(y,x,1); } dijikstra(1); cout<<dis[n]-1; return 0; }
J
简单模拟

#include<bits/stdc++.h> using namespace std; int n; char s[25][25]; bool check1() { int cnt1=0,cnt2=0,cntb=0; for(int j=1;j<=n;j++) { if(s[1][j]=='B') { cnt1++,cntb++; if(cnt2>=3) return 0; cnt2=0; } else { if(cnt1>=3) return 0; cnt1=0; cnt2++; } } if(cntb==n) return 0; int jsb=0; for(int i=1;i<=n;i++) { jsb=0;cnt1=0;cnt2=0; for(int j=1;j<=n;j++) { if(s[i][j]=='B') { cnt1++,jsb++; if(cnt2>=3) return 0; cnt2=0; } else { if(cnt1>=3) return 0; cnt1=0;cnt2++; } } if(jsb!=cntb) return 0; } return 1; } bool check2() { int cnt1=0,cnt2=0,cntb=0; for(int j=1;j<=n;j++) { if(s[j][1]=='B') { cnt1++,cntb++; if(cnt2>=3) return 0; cnt2=0; } else { if(cnt1>=3) return 0; cnt1=0; cnt2++; } } if(cntb==n) return 0; int jsb=0; for(int i=1;i<=n;i++) { jsb=0;cnt1=0;cnt2=0; for(int j=1;j<=n;j++) { if(s[j][i]=='B') { cnt1++,jsb++; if(cnt2>=3) return 0; cnt2=0; } else { if(cnt1>=3) return 0; cnt1=0;cnt2++; } } if(jsb!=cntb) return 0; } return 1; } int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>(s[i]+1); } if(check1()==0) { cout<<"0 "; return 0; } if(check2()==0) { cout<<"0 "; return 0; } cout<<"1"; return 0; }