1. 程式人生 > 其它 >2022 2-13&14

2022 2-13&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;
}