C#結合SMTP實現郵件報警通知
目錄
題目連結
https://ac.nowcoder.com/acm/contest/5667#question
B
題意:
使n個點中儘可能多的點在某個圓上,這個圓過原點,求最多有多少個點
思路:
列舉兩個點,與原點構成三角形,求外接圓圓心(注意三點共線)
將所有圓心排序,計算相同的圓心個數的最大值 \(mx\)
列舉求出 \(C_{res}^2=mx\)
程式碼:
#include<bits/stdc++.h> using namespace std; const int N=2005; const double eps=5e-7; int sgn(double x) {return fabs(x)<eps?0:(x>0?1:-1);} struct P { double x,y; P(){} P(double x,double y):x(x),y(y){} bool operator == (const P &a) const {return !sgn(x-a.x)&&!sgn(y-a.y);} bool operator < (const P &a) const {return sgn(x-a.x)<0||sgn(x-a.x)==0&&sgn(y-a.y)<0;} P operator + (const P &a) const {return P(x+a.x,y+a.y);} P operator - (const P &a) const {return P(x-a.x,y-a.y);} P operator * (const double &k) const {return P(x*k,y*k);} P operator / (const double &k) const {return P(x/k,y/k);} double operator ^ (const P &a) const {return x*a.y-y*a.x;} //叉積 P rotleft() {return P(-y,x);} //繞原點逆時針旋轉 90 度 }a[N],ps[N*N]; struct L { P s,t; L(){} L(P s,P t):s(s),t(t){} bool parallel(const L &a) {return sgn((t-s)^(a.t-a.s))==0;} //平行 P cross_point(L a) { //兩直線交點 需保證不平行不重合 double t1=(t-s)^(a.t-a.s); double t2=(t-a.t)^(a.t-a.s); double l=(t1==0?0:t2/t1); P dd=P(t.x-(t.x-s.x)*l,t.y-(t.y-s.y)*l); return dd; } }; P compute_circle_center(P a,P b,P c) { if(L(a,b).parallel(L(a,c))) return P(1e18,1e18); L u=L((a+b)/2,(a+b)/2+(b-a).rotleft()); L v=L((a+c)/2,(a+c)/2+(c-a).rotleft()); return u.cross_point(v); } int n,res,cnt; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf",&a[i].x,&a[i].y); for(int j=1;j<i;j++) { P t=compute_circle_center(P(0,0),a[i],a[j]); if(t.x==t.y&&fabs(t.x-1e18)<eps) continue; ps[++cnt]=t; } } if(cnt==0) res=1; else { sort(ps+1,ps+1+cnt); P pre=ps[1]; int tot=1,mx=1; for(int i=2;i<=cnt;i++) { if(ps[i]==ps[i-1]) tot++,mx=max(mx,tot); else tot=1,pre=ps[i]; } for(int i=n;i>=1;i--) if(i*(i-1)/2==mx) {res=i;break;} } printf("%d\n",res); return 0; }
C
題意:
在無根樹中選擇最少的鏈覆蓋所有的邊至少一次
思路:
選擇一個非葉子節點為根,按照 dfs 序記錄下所有葉子
記 \(l[i]\) 為按 dfs 序排序後排為 \(i\) 的葉子節點,\(cnt\) 為葉子個數
當 \(cnt\) 為偶數,構造的鏈為 \(l[i]\rightarrow l[cnt/2+1],l[i+1]->l[cnt/2+2],...,l[cnt/2]\rightarrow l[cnt]\)
設某條邊的兒子節點所覆蓋的葉子節點的區間為 \([L,R]\)
當 \(R\le cnt/2\),這條邊會被 \(l[R]\rightarrow l[R+cnt/2]\) 覆蓋
當 \(L>cnt/2\),這條邊會被 \(l[L-cnt/2]\rightarrow l[L]\) 覆蓋
否則因為根的度大於 \(1\),所以 \(L\ne 1\),\(R\ne cnt\) 必有一個條件滿足,若 \(L\ne 1\),這條邊會被 \(l[1]\rightarrow l[cnt/2+1]\) 覆蓋,若 \(R\ne cnt\),這條邊會被 \(l[cnt/2]\rightarrow l[cnt]\) 覆蓋
當 \(cnt\) 為奇數,則給匹配剩下那個葉子節點隨意匹配一個葉子節點即可
如果以一個葉子節點為根,將根加在按 dfs 序排序後的葉子節點的陣列最後即可
程式碼:
#include<bits/stdc++.h> using namespace std; const int N=2e5+5; int n,cnt[N],lf[N],tot; vector<int> G[N]; void dfs(int u,int fa) { cnt[u]=0; for(auto v:G[u]) { if(v==fa) continue; dfs(v,u); cnt[u]++; } if(!cnt[u]||u==1&&cnt[u]==1) lf[++tot]=u; } int main() { scanf("%d",&n); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v),G[v].push_back(u); } dfs(1,0); printf("%d\n",tot+1>>1); for(int i=1;i<=tot/2;i++) printf("%d %d\n",lf[i],lf[tot-i+1]); if(tot&1) printf("%d %d\n",lf[tot/2+1],1); return 0; }
D
題意:
求兩個時刻差多少秒
思路:
分別換算兩個時刻在這一天的秒數,求差
程式碼:
#include<bits/stdc++.h>
using namespace std;
char a[10],b[10];
int get(char c) {
return c-'0';
}
int main() {
scanf("%s%s",a,b);
int ha=get(a[0])*10+get(a[1]),hb=get(b[0])*10+get(b[1]);
int ma=get(a[3])*10+get(a[4]),mb=get(b[3])*10+get(b[4]);
int sa=get(a[6])*10+get(a[7]),sb=get(b[6])*10+get(b[7]);
printf("%d\n",abs(ha*3600+ma*60+sa-hb*3600-mb*60-sb));
return 0;
}
F
題意:
一個 \(n*m\) 的矩陣,每個單元格 \(A_{i,j}=lcm(i,j)\),求所有 \(k*k\) 的子矩陣中的最大值的和
思路:
二維滑動視窗
暴力求 \(A\) 為 \(O(nmlogn)\),考慮 \(O(nm)\) 的求法(見程式碼)
設 \(mx[i][j]\) 為以 \((i,j)\) 為右上角的子矩陣中的最大值,這樣就不會對後面的更新產生影響
程式碼:
#include<bits/stdc++.h>
using namespace std;
const int N=5005;
int n,m,k,a[N][N],gcd[N][N];
long long res;
deque<int> dq;
int main() {
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!gcd[i][j])
for(int k=1;i*k<=n&&j*k<=m;k++)
gcd[i*k][j*k]=k,a[i*k][j*k]=i*j*k;
for(int i=1;i<=n;i++) {
dq.clear();
for(int j=1;j<=m;j++) {
if(!dq.empty()&&j-dq.front()+1>k) dq.pop_front();
while(!dq.empty()&&a[i][dq.back()]<=a[i][j]) dq.pop_back();
dq.push_back(j);
if(j-k+1>0) a[i][j-k+1]=a[i][dq.front()];
}
}
for(int j=1;j<=m;j++) {
dq.clear();
for(int i=1;i<=n;i++) {
if(!dq.empty()&&i-dq.front()+1>k) dq.pop_front();
while(!dq.empty()&&a[dq.back()][j]<=a[i][j]) dq.pop_back();
dq.push_back(i);
if(i-k+1>0) a[i-k+1][j]=a[dq.front()][j];
}
}
for(int i=1;i<=n-k+1;i++) {
for(int j=1;j<=m-k+1;j++)
res+=a[i][j];
}
printf("%lld\n",res);
return 0;
}
J
題意:
求序列 \(\{1,2,3,...,n\}\) 按照 \(P\) 置換 \(k\)(\(10^8\le k\le 10^9\),\(k\) 為質數) 次後為 \(A\),已知 \(k\) 和 \(A\),求按照 \(P\) 置換一次後的序列
思路:
設原序列為 \(E\),\(E*P^k=P^k=A\)
找出所有迴圈置換,對於某個迴圈置換,設 \(sz\) 為環的大小,\(U\) 為 \(P\) 的子序列,\(V\) 為 \(A\) 的子序列,那麼 \(U^{k\%sz}=V\),\(V^{k^{-1}\%sz}=U\)
因為 \(\gcd(k,sz)=1\),又因為模數較小,所以對於 \(kx\%sz=1\) 可以列舉 \(x\) 求出逆元
程式碼:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,p[N],cnt,vis[N],res[N];
int m;
vector<int> v[N];
void find_cycle(int x) {
if(vis[x]) return;
vis[x]=cnt;
v[cnt].push_back(x);
find_cycle(p[x]);
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
for(int i=1;i<=n;i++) {
if(vis[i]) continue;
++cnt;
find_cycle(i);
int sz=v[cnt].size(),inv;
for(int j=0;j<sz;j++) if(1ll*m*j%sz==1) {inv=j;break;}
for(int j=0;j<sz;j++) res[v[cnt][j]]=v[cnt][(j+inv)%sz];
}
for(int i=1;i<=n;i++) printf("%d ",res[i]);
puts("");
return 0;
}