zoukankan      html  css  js  c++  java
  • 训练赛

    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;
    }
    
    
  • 相关阅读:
    keyset与entryset
    solr4.9r+ Eclipse 4.3+ tomcat 7.5 +winds7(二)
    如何解决This system is not registered with RHN.
    堆和栈的差别(转过无数次的文章)
    墨菲定律、二八法则、马太效应、手表定理、“不值得”定律、彼得原理、零和游戏、华盛顿合作规律、酒与污水定律、水桶定律、蘑菇管理原理、钱的问题、奥卡姆剃刀等13条是左右人生的金科玉律
    atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
    漫谈并发编程(二):java线程的创建与基本控制
    exosip
    PostgreSQL服务端监听设置及client连接方法
    APK反编译。
  • 原文地址:https://www.cnblogs.com/neflibata/p/12871808.html
Copyright © 2011-2022 走看看