gym103145

第19周解题报告2篇(7月5日-7月11日)

K - City

Gym - 103145K
题意:

n城市之间连接无方向的道路,每个道路都有能量,敌人发动攻击,来摧毁这些道路,如果敌人发动x的攻击,则所有能力小于等于x的道路都将被摧毁,问有有多少对城市可以到达对方

思路:

将所有的城市道路按照能量进行从小到大的排序,根据能量的大小,将它们进行合并,每次合并操作之后计算小于等于当前这个点有多少对城市,并存入res数组,根据每次的查询,判断是否大于最大的道路的能力,如果大于,则所有道路都摧毁,没有城市可以到达对方,否则根据lower_bound计算要查询的是res数组中的第几个值

要注意的是,要进行lower_bound,则需要先将数组进行排序,排序的时候要注意是n还是m。多组样例,每次需要初始化res=0

代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#define int long long
typedef long long ll; 
using namespace std;
typedef pair<int,int> PII;
const int N=2e5+5;
pair<PII,int>a[N];
PII p;
int f[N];
int cnt[N];
int ans=0;
int W[N];
int n,m,Q;
int res[N];//存放有多少对城市
bool cmp(pair<PII,int> xx,pair<PII,int> yy){
	return xx.second<yy.second;
}
int find(int x){
    if (f[x] != x) 
		f[x] = find(f[x]);
    return f[x];
}
void merge(int a,int b){
	int aa=find(a);
	int bb=find(b);
	if(aa!=bb){
		f[aa]=bb;
//		cout << "********"<<aa << " " << bb << endl;
//		cout << cnt[aa] << " " << cnt[bb] << endl;
		ans=ans+cnt[aa]*cnt[bb];
//		cout <<"*" << ans <<endl;
		cnt[bb]=cnt[bb]+cnt[aa]; 
		cnt[aa]=0;
	}
}
void init(){
	ans=0;//记得初始化res
	for(int i=1;i<=n;i++){
		f[i]=i;//用于存父节点
		cnt[i]=1;//用于计算有多少对城市
	}
}
signed main()
{
    //防止超时
	ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
	int t;
	cin >> t;
	while(t--){
		cin >> n >> m >> Q;
		init();//多组样例初始化
		for(int i=1;i<=m;i++){
			int x,y,w;
			cin >> x >> y >> w;
			p.first=x;
			p.second=y;
			a[i].first=p;//城市道路两端点
			a[i].second=w;//道路的能量
			W[i]=w; //城市道路的能量存入W
		} 
		sort(a+1,a+1+m,cmp);
		for(int i=m;i>=1;i--){
			merge(a[i].first.first,a[i].first.second);
			res[i]=ans;
		}
		sort(W+1,W+1+m);//注意要排序
//		for(int i=1;i<=m;i++){
//			cout << res[i];
//		}
		while(Q--){
			int x;
			cin >> x;
//			for(int i=1;i<=m;i++){
//				if(W[i]>=x){
//					temp=i;
//					break;
//				}
//			}
//			cout << temp << "*" << endl;
			if(x>a[m].second){//所有城市道路都摧毁
				cout << 0 << endl;
			}
			else{
				int temp=lower_bound(W+1,W+1+m,x)-W;
				cout << res[temp] << endl;	
			}
		}
	}
	return 0;
 } 
 /**
 5 
 2 1 2
 1 2 4
 3
 **/

J - Transform

Gym - 103145J

题意:

在三维空间内给出两个点(a,b,c)和(x,y,z),前一个点与原点所连成的直线为l,将第二个点绕直线l旋转r度和-r度,输出旋转后纵坐标高的那个点的坐标

思路:

假设旋转轴的单位向量为(vx,vy,vz),旋转前的坐标为(oldx,oldy,oldz),旋转后的坐标为(nx,ny,nz),旋转角度为theta,则有公式

node get(double oldx, double oldy, double oldz, double vx, double vy, double vz, double theta){
    double r = theta * PI / 180;
    double c = cos(r);
    double s = sin(r);
    double nx = (vx*vx*(1 - c) + c) * oldx + (vx*vy*(1 - c) - vz*s) * oldy + (vx*vz*(1 - c) + vy*s) * oldz;
    double ny = (vy*vx*(1 - c) + vz*s) * oldx + (vy*vy*(1 - c) + c) * oldy + (vy*vz*(1 - c) - vx*s) * oldz;
    double nz = (vx*vz*(1 - c) - vy*s) * oldx + (vy*vz*(1 - c) + vx*s) * oldy + (vz*vz*(1 - c) + c) * oldz;
    return node(nx, ny, nz);
}

如果setprecision(n)与setiosflags(ios::fixed)合用,可以控制小数点右边的数字个数。格式为

if(p1.z>p2.z) cout<<fixed<<setprecision(9)<<p1.x<<" "<<p1.y<<" "<<p1.z<<endl;
else cout<<fixed<<setprecision(9)<<p2.x<<" "<<p2.y<<" "<<p2.z<<endl
代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#define PI acos(-1)
#include<bits/stdc++.h>
typedef long long ll; 
using namespace std;
typedef pair<int,int> PII;

struct node{
    node(double _x, double _y, double _z){
        x = _x;
        y = _y;
        z = _z;
    }
    double x;
    double y;
    double z;
};

node get(double oldx, double oldy, double oldz, double vx, double vy, double vz, double theta){
    double r = theta * PI / 180;
    double c = cos(r);
    double s = sin(r);
    double nx = (vx*vx*(1 - c) + c) * oldx + (vx*vy*(1 - c) - vz*s) * oldy + (vx*vz*(1 - c) + vy*s) * oldz;
    double ny = (vy*vx*(1 - c) + vz*s) * oldx + (vy*vy*(1 - c) + c) * oldy + (vy*vz*(1 - c) - vx*s) * oldz;
    double nz = (vx*vz*(1 - c) - vy*s) * oldx + (vy*vz*(1 - c) + vx*s) * oldy + (vz*vz*(1 - c) + c) * oldz;
    return node(nx, ny, nz);
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        double a,b,c,x,y,z,r;
        cin>>a>>b>>c>>x>>y>>z>>r;
        double len=sqrtf(a*a+b*b+c*c);
        node p1=get(x,y,z,a/len,b/len,c/len,r);
        node p2=get(x,y,z,a/len,b/len,c/len,-r);
        if(p1.z>p2.z){
			printf("%.9lf %.9lf %.9lf\n",p1.x,p1.y,p1.z);
//			cout << p1.x << " " << p1.y << " " << p1.z << endl;
		}
		else{
			printf("%.9lf %.9lf %.9lf\n",p2.x,p2.y,p2.z);
//			cout << p2.x << " " << p2.y << " " << p2.z << endl;
		}
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值