2022 2-13&14
阿新 • • 發佈:2022-02-14
https://ac.nowcoder.com/acm/contest/28513/E
題意:
有一個多邊形的垃圾和一個通道,可以任意旋轉多邊形,問通道的直徑最小需要多少才能讓多邊形通過。
思路:
多邊形的形狀是沒有價值的,所以直接求出這些頂點的凸包。
然後對於凸包的每條邊,求出每個點到這條邊的最大距離,再求出這些最大距離中的最小距離。
#include <iostream> #include <bits/stdc++.h> using namespace std; #define eps 1e-9 #define pi acos(-1.0) int sgn(double d){ if(fabs(d)<eps) return 0; if(d>0) return 1; return -1; } struct Point { double x,y; Point (){} Point (double _x,double _y){x=_x;y=_y;} Point operator - (const Point &b) //直接減成 向量 const{ return Point(x-b.x,y-b.y); } double operator * (const Point &b) //過載運算子 倆向量 叉積 const{ return x*b.y-y*b.x; } double operator ^(const Point &b) //過載運算子 倆向量 點積 const{ return x*b.x + y*b.y; } }p[111],ans[111]; int n; bool cmp(Point a,Point b){ if(a.x==b.x) return a.y<b.y; return a.x<b.x; } int convex(){ sort(p,p+n,cmp); int m=0; for(int i=0;i<n;i++){ while(m>1&&sgn((ans[m-1]-ans[m-2])*(p[i]-ans[m-2]))==-1) m--; ans[m++]=p[i]; } int k=m; for(int i=n-2;i>=0;i--){ while(k>m&&sgn((ans[k-1]-ans[k-2])*(p[i]-ans[k-2]))==-1) k--; ans[k++]=p[i]; } if(n>1) k--; return k; } double length(Point x1){ return sqrt(x1^x1); } double dis(Point a,Point b,Point x){ Point x1=b-a; Point x2=x-a; return abs(x1*x2/length(x1)); } int main() { while(cin>>n,n){ for(int i=0;i<n;i++) cin>>p[i].x>>p[i].y; int mm=convex(); double res=1e6*1.0; for(int i=0;i<mm;i++){ double maxn=0; for(int j=0;j<mm;j++){ if((ans[j].x==ans[i].x&&ans[i].y==ans[j].y)||(ans[j].x==ans[(i+1)%mm].x&&ans[j].y==ans[(i+1)%mm].y)) continue; else{ double an=dis(ans[i],ans[(i+1)%(mm)],ans[j]); maxn=max(an,maxn); } }res=min(res,maxn); } printf("%.9lf\n",res); } return 0; }
https://ac.nowcoder.com/acm/contest/28513/F
題意:
有一個N邊形的車,車速為v,你在原點,你的速度為u,想要到達(0,w),問人最快到達(0,w)點的時間。顯然,車如果擋住你,你就不能走。
思路:
你走過去的情況就分兩種:車對你沒造成影響,車對你造成影響。 當車對你沒造成影響又分兩種情況:你的速度太快了,車的速度太快了。 分析這些情況 1:你的速度太快了。車的任意一點都到達不了你的位置。既 xi/v>yi/u。 2:車的速度太快了,你到達 車任意一點在y軸的投影時,車已經過去了。既xi/v<yi/u. 3:車對你造成影響,此時你需要調整速度來躲車,我們可以換一種角度看,當車最後一個點通過的時候,你在內個點上, 此時需要的時間就是車走xi 速度為v所需要的時間,再後面的路程(w-yi),你以速度u走。
https://www.luogu.com.cn/problem/P1045
高精度快速冪
本題P<=3100000,所以不能去對整個數進行乘法運算.
於是我們可以直接對後五百位進行計算,並用壓位高精和快速冪優化;
程式碼:
#include <bits/stdc++.h> using namespace std; int f[1001],p,res[1001],sav[1001],s;//sav[]是暫存計算過程的結果的陣列 void result_1(){ memset(sav,0,sizeof(sav)); for(int i=1;i<=500;i++)//乘法無倒正 for(int j=1;j<=500;j++) sav[i+j-1]+=res[i]*f[j]; for(int i=1;i<=1000;i++){//處理進位 sav[i+1]+=sav[i]/10; sav[i]=sav[i]%10; } for(int i=0;i<=1000;i++) res[i]=sav[i]; //儲存結果 } void result_2(){ memset(sav,0,sizeof(sav)); for(int i=1;i<=500;i++)//迴圈到500即可,不用到1000 for(int j=1;j<=500;j++) sav[i+j-1]+=f[i]*f[j];//乘法無倒正 for(int i=1;i<=1000;i++){ sav[i+1]+=sav[i]/10; sav[i]=sav[i]%10; } for(int i=0;i<=1000;i++) f[i]=sav[i];//儲存結果 } int main(){ cin>>p; s=(int)(log10(2)*p)+1;//log10是自帶函式 res[1]=1;//初始化應該是1 f[1]=2;//重要初始化 f[]是2的p次方的結果,初始化應該是2而不是1 cout<<s<<endl; while(p) {//計算2的p次方 if(p&1) result_1(); p>>=1; result_2(); } res[1]-=1;//2的p次方-1 for(int i=500;i>=1;i--){ if(i!=500&&i%50==0) cout<<endl; cout<<res[i]; } return 0; }
https://codeforces.com/contest/1637/problem/E
題意:
給長度為n的陣列
計算倆不同數字 出現的次數和*倆數字之和 最大值
x出現 cntx次 ; y出現cnty次
ans=max(ans,(cnts+cnty)*(x+y));
思路:
用map記錄陣列每個數x出現次數c
用vector<>o[] 儲存相同次數c的數x(v[c].push(x)) 並對v[c]內元素由大到小儲存
用vector<pair<>>b 儲存特殊快
遍歷o[]時 用二分函式判斷b是否含有
程式碼:
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
map<int, int> cnt;
for (int i=0;i<n;i++) {
int x;
cin>>x;
cnt[x]++;
}
vector<pair<int, int>> b;
for (int i = 0; i < m; i++) {
int x, y;
cin >>x>>y;
b.emplace_back(x, y);
b.emplace_back(y, x);
}
sort(b.begin(), b.end());
vector<long long> o[n];
for (auto &[x,c]:cnt)
o[c].push_back(x);
for (auto &v : o)
reverse(v.begin(),v.end());
long long ans= 0;
for (int cnt_x = 1; cnt_x < n; cnt_x++)
for (int x : o[cnt_x])
for (int cnt_y = 1; cnt_y <= cnt_x; cnt_y++)
for (auto y : o[cnt_y])
if (x != y && !binary_search(b.begin(), b.end(), pair<int, int>{x, y})) {
ans= max(ans, 1ll * (cnt_x + cnt_y) * (x + y));
break;
}
cout << ans << '\n';
}
int main() {
int t;
cin >> t;
while (t--)
solve();
}
https://codeforces.com/contest/1637/problem/D
思路:
對於一個位置i上的值x的貢獻為自身平方的n-1倍和自身與其他數進行乘積的2倍之和
假設有四個數a,b,c,d;
貢獻: (n-1)*(a*a+b*b+c*c+d*d)+(2ab+2ac+2ad+2bc+2bd+2cd)
=(n-2)*(a*a+b*b+c*c+d*d)+a*(a+b+c+d)+b*(a+b+c+d)+c*(a+b+c+d)+d*(a+b+c+d)
=(n-2)*(a*a+b*b+c*c+d*d)+(a+b+c+d)*(a+b+c+d)
程式碼:
#include <iostream>
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[111],b[111];
int n;
int dp[111][10005];
int main()
{
int T;
cin>>T;
while(T--){
memset(dp,0,sizeof(dp));
int n;
cin>>n;
ll ans=0;
for(int i=0;i<n;i++) cin>>a[i],ans+=(a[i]*a[i]);
for(int i=0;i<n;i++) cin>>b[i],ans+=(b[i]*b[i]);
ans=(n-2)*ans;
ll sum=0,su=0;
for(int i=0;i<n;i++)
sum+=max(a[i],b[i]),su+=a[i]+b[i];
dp[0][a[0]]=1,dp[0][b[0]]=1;
for(int i=1;i<n;i++){
for(int j=0;j<=sum+5;j++){
if(dp[i-1][j])
dp[i][j+a[i]]=1,dp[i][j+b[i]]=1;//前i個數 a陣列的可能值j
}
}
ll res=1e9;
for(int i=0;i<=sum+5;i++)
if(dp[n-1][i])
res=min(res,i*i+(su-i)*(su-i)); //遍歷
cout<<res+ans<<endl;
}
return 0;
}