訓練賽

A - Engines
題目鏈接:https://vjudge.net/contest/343420#status/Zreo917/A
思路:每個點都可以看作是一個起點是原點的向量,兩向量相加,夾角越小時合向量的模越大(夾角小於90º)所以爲了找到那個最遠的點,需要讓每個向量和與他夾角最小的向量相加,所以就要用到極角排序,對每一點暴力遍歷,同時更新最大值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000;
struct node
{
	int x,y;
	double d;
}e[maxn];
bool cmp(node a,node b)
{
	return a.d<b.d;
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>e[i].x>>e[i].y;
		e[i].d=atan2(e[i].y,e[i].x);
	}
	sort(e,e+n,cmp);
	ll ans=0;
	for(int i=0;i<n;i++)
	{
		ll dx=e[i].x,dy=e[i].y;
		ans=max(ans,(ll)dx*dx+dy*dy);
		for(int j=(i+1)%n;j!=i;j=(j+1)%n)//防止數組越界兩次都要取餘
		{
			dx=dx+e[j].x;dy=dy+e[j].y;
			ans=max(ans,(ll)dx*dx+dy*dy);
		}
	}
	printf("%.15lf",sqrt(ans)); 
	return 0;
 } 

B - Consecutive Integers
題意:
給你n個數(1~n) 求選k個連續數的方案 n-k-1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
	int n,k;
	cin>>n>>k;
	cout<<n-k+1;
	return 0;
}

C - ModSum
題目鏈接:https://vjudge.net/contest/343420#problem/C
題意:
有n個數的一個集合(1~n),求1到n這那個數對集合內的數取餘後的和的最大值
爲是餘數最大 那麼全都對n取餘 則和爲: k*(k-1)/2

在這裏插入代碼片#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
	ll n,k;
	cin>>n;
	ll res=n*(n-1)/2;
	cout<<res;
	return 0;
}

D - Shortest Path on a Line
鏈接:https://vjudge.net/contest/343420#problem/D
題意: 有n的點在一條線上(標號1~n) 每給出 l,r,w 就在 l 和 r之間任意兩點之間加權值爲 w的無向邊 一根一根加肯定會超時的 怎麼辦呢 在l和r 之間加一條權值是我都變 他們相鄰中間點加權爲0的反向邊 (即:點i->點i-1 權值爲0) 這樣是不是對任意的L ≤ s < t ≤ R,都有路徑爲 s->…-> L -> R -> …->t的路實現 s->t 而且 權值剛好是w (太妙了!!!) 之後就好辦了 跑一遍最短路就行了

#include <bits/stdc++.h>
#define ll long long
#define pll pair<ll, ll>
#define pii pair<int, int>
#define f first
#define se second
#define pb push_back
#define ld long double
 
using namespace std;
 
 
const int N = 2e5 + 123;
const int MAXN = 1e5 + 12;
const int inf = 1e9 + 7;
const ll mod = 1e9 + 7;
 

ll n, m, d[N];
bool vis[N], is[N];
vector <pll> g[N];
 
 
void djk() {
    priority_queue <pair<ll, ll> > q;
    q.push({0, 1});
    pair<ll, ll> tmp;
    ll u, w;
    while (!q.empty()) {
        tmp = q.top();
        q.pop();
        u = tmp.se;
        w = -tmp.f;
        if (vis[u])
            continue;
        vis[u] = 1;
        d[u] = w;
        if (u != 1 && !vis[u - 1])
            q.push({-w, u - 1});
        for (int i = 0; i < g[u].size(); i++)
            if (!vis[g[u][i].f])
                q.push({-w - g[u][i].se, g[u][i].f});
    }
} 
 
 
int main() {
    cin >> n >> m;
    ll x, y, z;
    for (int i = 1; i <= m; i++) {
        cin >> x >> y >> z;
        g[x].pb({y, z});
    }
    memset(d, -1, sizeof(d));
    djk();
    cout << d[n];
    return 0;
}

E - Counting of Trees
題目鏈接:https://vjudge.net/contest/343420#problem/E
樹的節點編號1到n;給你一個數組d[n],d[i]表示節點1到節點 i 的邊的數量,求滿足條件的樹的個數
假設 到1點距離爲i(i>1)的點有 num[i] 個,那麼這幾個節點都可以與距離爲i-1的點 相連,每個點有num[i-1]種情況,這一距離就要pow(num[i-1] , num[i]) 種情況了,遍歷一遍就可以了 除此之外還有幾種特殊情況需要特判

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
ll ksm(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1) ans=ans*a%mod;
		b/=2;
		a=a*a%mod;
	}
	return ans;
}
int main()
{
	ll n,x,ans=1,s[100100],num[100100];
	memset(num,0,sizeof num);
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>x;
		if(!i&&x) ans=0;//d[1]>0
		else if(i&&!x) ans=0;//d[i]==0
		num[x]++;
	}
	if(ans)
	{
//		ans=num[1];
		for(int i=2;i<n;i++)
			if(num[i]&&num[i-1])
				ans=ans*ksm(num[i-1],num[i])%mod;
			else if(num[i]&&!num[i-1]) ans=0;//跳過了一些點 是不可能的
	}
	cout<<ans;
	return 0;
}

F - Monsters Battle Royale
題目鏈接:https://vjudge.net/contest/343420#problem/F
題意:n個人有不同的健康值,健康值地的可以攻擊健康值高的人,被攻擊的人的健康值減少量是攻擊人的健康值求最後的 最小值.
思路:
求兩個人最後的健康值不就是輾轉相除法,即求最大公因數

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int main()
{
	ll n,s[maxn];
	scanf("%lld",&n);
	for(int i=0;i<n;i++)
		scanf("%lld",&s[i]);
	ll ans=s[0];
	for(int i=1;i<n;i++)
		ans=__gcd(ans,s[i]);
	cout<<ans;
}

G - Powerful Discount Tickets
題目鏈接:https://vjudge.net/contest/343420#problem/G
題意:
共有n件商品,你有m張券,需要把所有商品買完,有y張券買價值爲x的商品你需要付x/pow(2,y) 元(向下取整),問需要最少付多少元
思路:
x/pow(2,y) 就是說每用一張券,需要付的錢就是當前商品價值的一半(整除)
爲了實現最小,就要儘可能多的去除價值高的商品,就可以一張一張的去除,每張券都要去除當前價值最高的那個,就要用優先隊列了

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

int main()
{
	priority_queue<ll,vector<ll>,less<ll> > q;//從大到小排,價值高的優先級高 從小到大排是 priority_queue<ll,vector<ll>,greater<ll> > q;
	int n,m;
	ll x;
	cin>>n>>m;
	for(int i=0;i<n;i++)
	{
		cin>>x;
		q.push(x);
	}
	while(m)
	{
		ll t=q.top()/2;
		q.pop();
		q.push(t);
		m--;
	}
	ll sum=0;
	while(!q.empty())
	{
		sum+=q.top();
		q.pop();
	}
	cout<<sum;
	return 0;
}

H - Attack Survival
題目鏈接:https://vjudge.net/contest/343420#problem/H
題意:n個人初始有k分,共回答q個問題,除了回答正確的人其他人全部減一分 勝者分數不變,經過k個問題後分數大於0的人勝 並輸出每個人是否勝
勝者不變,輸者減一 是不是相當於勝者加一,不過最後不是判斷d[i]是否大於0了而是是否大於k-q

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int main()
{
	int c[maxn],num[maxn],n,q,k,x;
	memset(num,0,sizeof num);
	scanf("%d%d%d",&n,&k,&q);
	for(int i=1;i<=q;i++)
	{
		scanf("%d",&x);
		num[x]++;
	}
	for(int i=1;i<=n;i++)
	{
		if(num[i]<=q-k) puts("No");
		else puts("Yes");
	}
	return 0;
}

J - Kleene Inversion
題目鏈接:https://vjudge.net/contest/343420#problem/J
題意: 有一個數字串 將這個串循環k次 求任意 i>j 且s[i]<s[j]的情況數
思路: 預處理給定字符串,求h[i]和sum[i] (h[i]:第i個數後有幾個數比它小; sum[i]: 全串有幾個數比它小) 對於整個循環串 ,第一個子串的第i個數後邊比他小的數有 h[i]+sum[i](k-1) 而第二子串有 h[i]+sum[i](k-2) 以此類退 第k個子串有h[i]
所以: 所有子串的第i個數有 h[i]k+sum[i](k*(k-1)/2) ,遍歷一遍相加即可(記得取模)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int main()
{
	int n,k,s[5000];
	cin>>n>>k;
	for(int i=0;i<n;i++)
	{
		scanf("%d",&s[i]);
	}
	int h[5000],sum[5000];
	memset(h,0,sizeof h);
	memset(sum,0,sizeof sum);
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<i;j++)
			if(s[i]>s[j])
				sum[i]++;
		for(int j=i+1;j<n;j++)
			if(s[i]>s[j])
				h[i]++;
		sum[i]+=h[i];
	}
	ll ans=0;
	//cout<<(ll)k*(k-1)/2%mod<<endl; 
	for(int i=0;i<n;i++)
	{
		ans=(ans%mod+(ll)h[i]*k%mod)%mod;
		ans=(ans%mod+((((ll)k*(k-1)/2)%mod)%mod*sum[i])%mod)%mod;//每個可能爆 ll 的情況都要mod掉(k*k還會爆 int)
	}
	cout<<ans%mod;
	return 0;
}```
K - Two Contests 
鏈接:https://vjudge.net/contest/343420#problem/K
思路:將所有區間分爲兩個集合,求兩個集合公共區間和的最大值;
先求出來	最大區間左端點lmax(區間記爲q) 最小區間右端點rmin(區間記爲p)
那麼會有兩種情況 qp在同一集合,pq不在一個集合
pq在同一集合,那麼這個集合的公共區間就確定了,不管其他區間是否在這個集合 公共區間的長度就是max(rmin-lmax+1,0) (確保值非負)	那麼把其他區間最長的那個單獨放到另一集合所得到答案是最大
如果pq不在同一集合, ,先把所有區間按l從小到大排序,開lx[i]表示前i個集合的最大左端點  rx[i]表示 前 i個區間的最小右端點	ly[i] 表示第i個區間 後邊區間的最大右端點,ry[i] 表示	表示第i個區間 後邊區間的最小左端點 ,數組更新之後就該求最大公共區間了,遍歷n個區間,到第i個時	max(0,rx[i]-lx[i]+1)表示前i個區間的最大公共區間,max(0,ry[i+1]-ly[i+1]+1) 表示其他區間的最大公共區間,按l排序後應該把所有最大可能的情況遍歷完了,求得這種情況的最大值,最後比較兩種情況的最大值

```cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
struct node
{
	int l,r;
}e[maxn];
bool cmp(node a,node b)
{
	return a.l<b.l;
}

int main()
{
	int n,p,q,lmax=0,rmin=0x3f3f3f3f;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		scanf("%d%d",&e[i].l,&e[i].r);
		if(lmax<e[i].l) lmax=e[i].l,p=i;
		if(rmin>e[i].r) rmin=e[i].r,q=i;
	}
		
	sort(e,e+n,cmp);
	int lx[maxn],rx[maxn];
	lx[0]=e[0].l,rx[0]=e[0].r;
	for(int i=1;i<n;i++)
	{
		lx[i]=max(lx[i-1],e[i].l);
		rx[i]=min(rx[i-1],e[i].r);
	}
	int ly[maxn],ry[maxn];
	ly[n-1]=e[n-1].l,ry[n-1]=e[n-1].r;
	for(int i=n-2;i>=0;i--)
	{
		ly[i]=max(ly[i+1],e[i].l);
		ry[i]=min(ry[i+1],e[i].r);
	int ans1=0,ans2=0;
	for(int i=0;i<n;i++)
		if(i!=q&&i!=p)
		ans1=max(ans1,max(0,rmin-lmax+1)+e[i].r-e[i].l+1);
	for(int i=0;i<n-1;i++)
	{
		ans2=max(ans2,max(0,rx[i]-lx[i]+1)+max(ry[i+1]-ly[i+1]+1,0));
	}
//	cout<<ans1<<' '<<ans2<<endl;
	cout<<max(ans1,ans2)<<endl;
	return 0;
 } 

M - AB Substrings
鏈接:https://vjudge.net/contest/343420#problem/M
題意: 有n個字符串,問拼接後出現字符"AB"的個數,
遍歷每個字符串, 串首是B而且串尾是A時 num1++ ; 只有串首是B時 num2++; 只有串尾是A時 num3++; 字符串中間出現AB時 ans++,最後再比較 num1,num2,num3可以拼出的最多的AB

#include <bits/stdc++.h>
typedef  long long ll;

 
using namespace std;
 
 
const int N = 2e5 + 123;
const int MAXN = 1e5 + 12;
const int inf = 1e9 + 7;
const ll mod = 1e9 + 7;
ll n, m, d[N];
bool vis[N];
vector <pair<ll,ll> > g[N];
void djk() {
    priority_queue <pair<ll, ll> > q;
    q.push({0, 1});
    pair<ll, ll> tmp;
    ll u, w;
    while (!q.empty()) {
        tmp = q.top();
        q.pop();
        u = tmp.second;
        w = -tmp.first;
        if (vis[u])
            continue;
        vis[u] = 1;
        d[u] = w;
        if (u != 1 && !vis[u - 1])
            q.push({-w, u - 1});
        for (int i = 0; i < g[u].size(); i++)
            if (!vis[g[u][i].first])
                q.push({-w - g[u][i].second, g[u][i].first});
    }
} 
 
int main() {
    cin >> n >> m;
    ll x, y, z;
    for (int i = 1; i <= m; i++) {
        cin >> x >> y >> z;
        g[x].push_back({y, z});
    }
    memset(d, -1, sizeof(d));
    djk();
    cout << d[n];
    return 0;
}

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