2020年西北工業大學“編程之星”程序設計挑戰賽

羣裏有人發比賽密碼就去打了打,題目質量真不錯。傳送門
兩道水題就不貼了。
A 先給數組排序,再求前綴和,然後對於每次詢問的x,y保持x<y,
先找到最後一個小於x的下標 l ,那麼前l個員工到x的距離最短等於l*x-前綴和;
第一個大於y的下標 r ,那麼r之後的員工到y的距離最短用前綴和也可以求,
然後看x和y之間的,當x+y是奇數時(x+y)/2到x最近,當x+y是偶數時(x+y)/2到x和y距離一樣近,所以就令小於等於(x+y)/2的走向x,其餘的走向y,還是用前綴和計算。

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
typedef long long ll;
int n,t,a[N],q,x,y;
ll sum[N];
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
    while(q--)
    {
    	scanf("%d%d",&x,&y);
    	if(x>y) swap(x,y);
    	int l=upper_bound(a+1,a+n+1,x)-a-1;
    	ll ans=1ll*l*x-sum[l];
    	int r=upper_bound(a+1,a+n+1,x+y>>1)-a-1;
    	ans+=(sum[r]-sum[l]-1ll*x*(r-l));
    	l=upper_bound(a+1,a+n+1,y)-a-1;
    	ans+=(1ll*(l-r)*y-sum[l]+sum[r]);
    	ans+=(sum[n]-sum[l]-1ll*(n-l)*y);
    	cout<<ans<<endl;
	}
}

F 四等分∠AOB。思路:先找∠AOB 的角平分線OC,再平分∠AOC 和∠BOC,
分成三次平分,二分角即可。(還有一種思路是當角的兩條邊長度相等時兩個端點的中點在角平分線上,延長邊不太好寫,縮小邊還是可以二分,不過邊的長度越小時誤差會越大可能會wa)。

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
const double eps=1e-15;
typedef long long ll;
#define pdd pair<double,double>
int n,t,a[N],q,x,y;
int xa,ya,xo,yo,xb,yb;
double check(double x1,double y1,double x2,double y2)//令點d爲(x1,y1),點e爲(x2,y2),返回∠dOe的cos值,∠AOB<180,二分之後小於90,cos函數就單調了
{
    double dx1=x1-xo,dy1=y1-yo,dx2=x2-xo,dy2=y2-yo;
    double d1=sqrt(dx1*dx1+dy1*dy1),d2=sqrt(dx2*dx2+dy2*dy2);
    return (dx1*dx2+dy1*dy2)/d1/d2;
}
pdd solve(double x1,double y1,double x2,double y2)//二分
{
    double l1=x1,l2=y1,r1=x2,r2=y2,mid1,mid2;
    for(int i=0;i<=50;i++)
    {
        mid1=(l1+r1)/2;
        mid2=(l2+r2)/2;
        if(check(x1,y1,mid1,mid2)>check(x2,y2,mid1,mid2))
        {
            l1=mid1;
            l2=mid2;
        }
        else r1=mid1,r2=mid2;
    }
    return {l1,l2};
}
int main()
{
    cin>>xa>>ya>>xo>>yo>>xb>>yb;
    pdd res=solve(xa,ya,xb,yb);
    pdd ans1=solve(xa,ya,res.first,res.second);
    pdd ans2=solve(xb,yb,res.first,res.second);    
    printf("%.10lf %.10lf\n",ans1.first,ans1.second);
    printf("%.10lf %.10lf\n",res.first,res.second);
    printf("%.10lf %.10lf",ans2.first,ans2.second);
}

G 首先的想法時先求乘積再分解質因數,但是乘積也太大了,早爆ll了。
然後可以發現每個數的範圍是1到9,可以直接統計區間內每個數的個數啊,不會還是不太好寫還要分情況,再回過頭來看第一句,分解質因數啊,存儲的時候就分解唄,最後統計質因數的個數答案不就出來了。

#include<bits/stdc++.h>
using namespace std;
const int N=100010,mod=998244353;
const double eps=1e-15;
typedef long long ll;
#define pii pair<int,int>
int n,t,a[N],m;
struct node
{
	int l,r;
	int num[10];
}tr[N<<2];
void pushup(int rt)
{
	for(int i=1;i<=9;i++)
		tr[rt].num[i]=tr[rt<<1].num[i]+tr[rt<<1|1].num[i];
}
void build(int rt,int l,int r)
{
	if(l==r) 
	{
		tr[rt]={l,l};
		int x=a[l];
		for(int i=2;i<=9;i++)//分解質因數
			while(x%i==0)
			{
				tr[rt].num[i]++;
				x/=i;
			}
	}
	else
	{
		tr[rt]={l,r};
		int mid= l+r>> 1;
		build(rt<<1,l,mid);
		build(rt<<1|1,mid+1,r);
		pushup(rt);
	}
}
void updata(int rt,int l,int r)
{
	if(tr[rt].l==l&&tr[rt].r==l) 
	{
		for(int i=1;i<=9;i++)//先清空再更改
			tr[rt].num[i]=0;
		for(int i=2;i<=9;i++)
			while(r%i==0)
			{
				r/=i;
				tr[rt].num[i]++;
			}
	}
	else 
	{
		int mid =tr[rt].l+tr[rt].r>>1;
		if(l<=mid) updata(rt<<1,l,r);
		else updata(rt<<1|1,l,r);
		pushup(rt);
	}
}
vector<int> query(int rt,int l,int r)
{
	if(l<=tr[rt].l&&tr[rt].r<=r)
	{
		vector<int> res(10);
		for(int i=1;i<=9;i++) res[i]=tr[rt].num[i];
	  return res;
	}
	int mid =tr[rt].l+tr[rt].r>>1;
	vector<int> ans(10,0);
	if(l<=mid) 
	{
		vector<int> res=query(rt<<1,l,r);
		for(int i=2;i<=9;i++) ans[i]+=res[i];
	}
	if(r>mid) 
	{
		vector<int> res=query(rt<<1|1,l,r);
		for(int i=2;i<=9;i++) ans[i]+=res[i]; 
	} 
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",a+i);
	build(1,1,n);
	while(m--)
	{
		int op,l,r;
		scanf("%d%d%d",&op,&l,&r);
		if(op==1)
		{
			updata(1,l,r);
		}
		else 
		{
			vector<int> res=query(1,l,r);
			ll ans=1;
			for(int i=2;i<=9;i++)//1的個數不用統計
				ans=ans*(res[i]+1)%mod;
			printf("%lld\n",ans);
		}
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章