2021年度训练联盟热身训练赛第三场

72 篇文章 5 订阅

A Circuit Math-模拟

题意:

规定+为|,-为!,*为&,给定你n个真值分别表示A-Z,T为真,F为假.让你进行一系列操作.求最后的真值.

思路:

直接模拟,注意我们呢输入用的getline前面加上getchar.其他也没什么了

    n = read();
    for(int i = 1 ; i <= n ; i++)
    {
        string c;
        cin >> c;
        if(c[0] == 'T')  op[i] = 1;
        else op[i] = 0;
    }

    string s;
    getchar();
    getline(cin, s);
    for(int i = 0 ; i < s.size() ; i++)
    {
        if(s[i] == ' ') continue;

        if(s[i] >= 'A' && s[i] <= 'Z')
        {
            st[++top] =  op[s[i] - 'A' + 1] ;
        }
        else  if(s[i] != '-')
        {
            int t1 = st[top];
            top--;
            int t2 = st[top];
            top--;
            if(s[i] == '+')
            {
                int t  = (t1 | t2);
                st[++top] = t;

            }
            else
            {
                int t  = (t1 & t2);
                st[++top] = t;
            }

        }
        else
        {
            int t1 = st[top];
            top--;
            st[++top] = (!t1);
        }

    }
    if(st[top] == 1) puts("T");
    else puts("F");
    

B Diagonal Cut-规律

题意:

给你一个nm的矩阵让你让你求一共多少个对角线将一个11的正方形分成面积相等的两份

思路:

找规律,我们先看n*n的话可以得出肯定是n个,

1*1                   1
1*2                    0
1*3                     1
1*4                        0   
1*5                   1
....
再看2*X的
2*2                 2
2*3                0
2*4                0 等同于两个1*2的
2*5                0
2*6                2    等同于两个1*3的
再看3*X
3*3                3
3*4                0
3*5                   1
3*6                0 相当于3个1*2的

我们其实观察可以得到:

  • 如果n==m那么一定是n个.
  • 如果n和m互质,若n和m都是奇数他中间那个一定是平分的其他的不能平分,所以是1.
  • 互质有一个或者都不是奇数那么一个都不平分.就是0
  • 剩下的就死和不互质,那我们转化整他们互质的情况乘以gcd即可,转换成互质的即除以gcd再取判断奇偶性,有偶数那么即使有gcd也是0,都是奇数,就直接输出gcd即可.
#include <stack>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
typedef unsigned long long ull;

#define x first
#define y second
#define sf scanf
#define pf printf
#define inf 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
#define debug(x) cout << #x << ": " << x << endl;

const int MOD = 10007;
const int mod = 998244353;
const int maxn = 2e5 + 1010;
const int dx[] = {1, 1, 1, 0, 0, -1, -1, -1};
const int dy[] = {1, 0, -1, -1, 1, -1, 1, 0};

ll a[26], b[maxn], c[maxn];
ll ans, n, m, len, k;
string str;
ll dp[maxn][50];
stack<int>s;
void solve()
{
    cin >> n >> m;

    if(n == m)
    {
        cout << n << endl;
        return ;
    }

    ll ans = __gcd(n, m);

    if(ans == 1 && n % 2 && m % 2)
    {
        cout << 1 << endl;
    }
    else if(ans == 1)
    {
        cout << 0 << endl;
    }
    else
    {
        if((n / ans) % 2 && (m / ans) % 2) cout << ans << endl;
        else cout << 0 << endl;
    }

}

int main()
{
    solve();
    return 0;
}

C Gerrymandering-枚举

D Missing Numbers-枚举

题意:

找出给出范围内没给出的数字.

思路:

直接暴力找即可

    n=read();
    int ma = 0 ;
    for(int i=1 ;i<=n ;i++)
    {
        int x = read();
        vis[x] =1 ;
        ma = max(ma,x);
    }
    int flag=1;
    for(int i=1 ;i<=ma ; i++)
    {
        if(vis[i]==0)
        {
            flag=0;
            cout<<i<<endl;
        }
    }
    if(flag) cout<<"good job";
 

G Research Productivity Index-概率DP

I Slow Leak-flody

J Stop Counting!–前缀思想优化

题意:

给出你n个数,你可以中间或者两段让他删去一段(连续的一段)让你求删去数之后或者不删数的最大平均数.

思路:

我们看题目数据量1e6所以肯定不能n^2,所以我们必须找到一个优化的方法,我一开始是尺取或者说双指针优化.但是不行,简单的提下:就是分别从两段出发选较大值题填充,肯定是不行的如果将一段的小值加上了另一端加了一个更小的在加一个更大的,就没了就像 1,1,1000,-1

正解:就是前缀维护一个前缀最大值,记录下标和平均值.然后从后面开始遍历一遍,取前一个的前缀最大即我们维护的前缀最大值.至于要求一下max即可.

#include <stack>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
typedef unsigned long long ull;

#define x first
#define y second
#define sf scanf
#define pf printf
#define inf 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
#define debug(x) cout << #x << ": " << x << endl;

const int MOD = 10007;
const int mod = 998244353;
const int maxn = 2e6 + 1010;
const int dx[] = {1, 1, 1, 0, 0, -1, -1, -1};
const int dy[] = {1, 0, -1, -1, 1, -1, 1, 0};


ll n;
double a[maxn], b[maxn],c[maxn],d[maxn];
double p[maxn];

void solve()
{
    cin >> n;
    double sum = 0.0;
    
   	double  ans=0.0;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        sum+=a[i];
        b[i]=sum*1.0/i;  
        ans=max(ans,b[i]);
    }
    
    sum=0;
   	for(int i=n;i>=1;i--){
   		sum+=a[i];
   		c[i]=sum*1.0/(n-i+1);
   		ans=max(ans,c[i]);
   	}

   	for(int i=1;i<=n;i++){
   		if(b[i]>=p[i-1]){
   			d[i]=i;
   			p[i]=b[i];
   		}else {
   			d[i]=d[i-1];
   			p[i]=p[i-1];
   		}
   	}
   	for(int i=n;i>=1;i--){
   		double s=(n-i+1)*c[i]+d[i-1]*p[i-1];
   		ll num=(n-i+1)+d[i-1];
   		ans=max(ans,s*1.0/num);   		
   	}


    printf("%.10lf\n", ans);
}

int main()
{
    ll t;
    //cin>>t;
    t = 1;
    while(t--)
    {
        solve();
    }
    return 0;
}

K Summer Trip-暴力枚举

题意

就是给出以一个只含’a’-'z’的序列,然后让你选长度至少为2的第一字符没有重复,最后一个字符也没有重复的子序列.

思路:

既然我们呢选出来的子序列中只有一个最后一个字符和第一个字符,那么我们可以直接来从最后一个字符入手,就是固定最后一个字符,我们找前面一次的字符开头(中间没有我们呢确定的最后一个字符)

void solve()
{
    cin >> str;
    ll len = str.size();
    str = " " + str;
    ll sum = 0;
    for(int i = 0; i < 26; i++)
    {
        mem(a, 0);
        for(int j = 1; j <= len; j++)
        {
            if(str[j] == i + 'a') /// i+'a'结尾
            {
                for(int k = 0; k < 26; k++)
                {
                    if(k != i && a[k]) sum++;
                    a[k] = 0;
                }
            }
            else
            {
                a[str[j]-'a']++;
            }
        }
    }
    cout << sum << endl;
}

M Zipline-计算几何

题意

给出两个杆长,给出你两杆的距离,给出你最低点的高度.让你求绳最短和最长

思路:

这个与高中力学中的晾衣杆模型一样.
首先看最短,其实就是两杆最高点的距离.
最长:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZwMVLxFt-1616328858214)(https://uploadfiles.nowcoder.com/images/20210321/432714694_1616328214281/9095EFBFBCD0CE84E872D3AB7F40C444 “图片标题”)]

我们需要知道中间这个最低点在那个位置,其实就是用到晾衣杆模型.最低点受力平衡,所以左三角与右三角相似,底边长度比等于杆长度比(较最低点比).这就求出水平长度,勾股定理求出两个边长度和,即可.
注意:有种可能就是,最低点与一杆高相等,相对高度就是0,可以直接写两杆最高点的距离(最长和最短相等)

#include <stack>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
typedef unsigned long long ull;

#define x first
#define y second
#define sf scanf
#define pf printf
#define inf 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
#define debug(x) cout << #x << ": " << x << endl;

const int MOD = 10007;
const int mod = 998244353;
const int maxn = 2e5 + 1010;
const int dx[] = {1, 1, 1, 0, 0, -1, -1, -1};
const int dy[] = {1, 0, -1, -1, 1, -1, 1, 0};


void solve()
{
    double w, g, h, r;
    cin >> w >> g >> h >> r;
    double a1 = g - r, a2 = h - r;
    if(a1==0&&a2==0){
    	printf("%.8lf %.8lf\n", w, w);
    	return;
    }
    else if(a1==0){
    	printf("%.8lf %.8lf\n", sqrt(w*w+a2*a2), sqrt(w*w+a2*a2));
    	return ;
    }else if(a2==0){
		printf("%.8lf %.8lf\n", sqrt(w*w+a1*a1), sqrt(w*w+a1*a1));
    	return ;
    }
    double b1 = double(w * (a1 *1.0/ (a1 + a2)));
    double b2 = w - b1;

    double maxx = sqrt(b1 * b1 + a1 * a1) + sqrt(a2 * a2 + b2 * b2);
    double minn = sqrt(fabs(g - h) * fabs(g - h) + w * w);
    printf("%.8lf %.8lf\n", minn, maxx);
}

int main()
{
    ll t;
    cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}	

中间几篇由队友@yiui巨巨@UpMing!提供.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值