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;
}