7.28 2020 Multi-University Training Contest 3题解及补题

7.28 2020 Multi-University Training Contest 3题解及补题

比赛过程

这场的1004一开始理解题意,不知道往哪个方向想,确定知识点不太准确。1009括号匹配的知识点,一开始考虑欠周全。

题解

1004 Tokitsukaze and Multiple

题意

给定两个数n和p,接下来是长度为n的序列。每次可以把序列相邻的两个数合并为两个数的和,数组的长度减1。求数组中是p的倍数的数最多有多少个。

解法

首先,如果单独的一个a[i]%p0,ans++,然后考虑剩下的数怎么组合。可以开一个set,如果a[i]%p0,ans++,set.clear()。如果a[i]%p!=0,记录两个值,分别是a[i]+a[i+1]……的和sum,然后把sum%p分别放入set里面,每次新的a[i]都检查sum%p的值是不是在set里面,如果在set里面,清空set,ans++

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std; 
int main() {
    int t;
    scanf("%d",&t);
    while(t--){
        ll n,p;
        scanf("%lld%lld",&n,&p);
        ll a[n+1];
        ll ans=0;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        set<int> st;
        ll sum=0;
        for(int i=1;i<=n;i++){
            if(a[i]%p==0){
                ans++;
                st.clear();
                sum=0;
                continue;
            }
            sum+=a[i];
            if(sum%p==0||(st.count(sum%p))){
                ans++;
                sum=0;
                st.clear();
                continue;
            }
            else{
                st.insert(sum%p);
            }
        }
        cout<<ans<<endl;
    }
}

1005 Little W and Contest

题意

给n个人与每个的能力值(2或1),组一个3人的队能力和至少5以上,同在一个集合的人不能组队,最开始每个人都在自己的集合,询问n-1次,每次将任意两人所在的集合合并之后输出多少种组队方案。

解法

构造一个二元多项式。

借助 x 表示人数,借助 y 表示战斗力。

则多项式中的项 \(kx^ay^b\) 表示:组成由 a 人组成战斗力为 b 的团队,方案总数为 k。

对于一个有 n 人战斗力为 1,m 人战斗力为 2 的连通块,则可以用多项式 \((nxy + mxy^2 + 1)\) 来表

示。添加连通块只要多项式乘进去,要删除连通块消除贡献只要多项式除回来即可。

由于幂较小,借助二维背包来做多项式乘除法即可。

正贡献 01 背包为多项式乘法,负贡献完全背包为多项式除法

代码

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
using namespace std;
const long long mod=1e9+7;
const int MAXN=100005;
struct Generating_function
{
    long long ki[4][7];//x y
    Generating_function()
    {
        memset(ki,0,sizeof(ki));
        ki[0][0]=1;
    }
    void init()
    {
        memset(ki,0,sizeof(ki));
        ki[0][0]=1;
    }
    void mult(long long a,long long b)
    {
        for(int i=3;i;--i)
        {
            for(int j=6;j;--j)
            {
                ki[i][j]+=a*ki[i-1][j-1]%mod;
                if(j>1)ki[i][j]+=b*ki[i-1][j-2]%mod;
                ki[i][j]%=mod;
            }
        }
    }
    void div(long long a,long long b)
    {
        for(int i=1;i<=3;++i)
        {
            for(int j=1;j<=6;++j)
            {
                ki[i][j]-=a*ki[i-1][j-1]%mod;
                if(j>1)ki[i][j]-=b*ki[i-1][j-2]%mod;
                ki[i][j]=(ki[i][j]%mod+mod)%mod;
            }
        }
    }
    long long get()
    {
        return (ki[3][5]+ki[3][6])%mod;
    }
}solve;
int fa[MAXN],a[MAXN],b[MAXN],x,n,u,v;
int findf(int x)
{
    return fa[x]==x?x:fa[x]=findf(fa[x]);
}
void unions(int x,int y)
{
    a[findf(y)]+=a[findf(x)];
    b[findf(y)]+=b[findf(x)];
    fa[findf(x)]=findf(y);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        solve.init();
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&x);
            fa[i]=i;
            a[i]=b[i]=0;
            if(x==1)++a[i];
            else ++b[i];
            solve.mult(a[i],b[i]);
        }
        printf("%lld\n",solve.get());
        for(int i=1;i<n;++i)
        {
            scanf("%d %d",&u,&v);
            solve.div(a[findf(u)],b[findf(u)]);
            solve.div(a[findf(v)],b[findf(v)]);
            unions(u,v);
            solve.mult(a[findf(u)],b[findf(u)]);
            printf("%lld\n",solve.get());
        }
    }
    return 0;
}

1006 X Number

题意

解法

代码

//将内容替换成代码

1007 Tokitsukaze and Rescue

题意

解法

代码

//将内容替换成代码

1008 Triangle Collision

题意

有一小球在一个边长为LL的等边三角形内运动

其拥有一个初始位置\((x,y)\)以及恒定速度\((V_x,V_y)\)

询问当第k次撞击三角形边缘时花费的时间

保证小球在前k次撞击不会撞到三角形的某个角

解法

主要在于旋转,因为看的大佬的博客,图片不会制作,这里放个图片链接

需要用到平面几何的知识,注意知识点储存

代码

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
using namespace std;
typedef long long ll;
const double eps=1e-12;
const double PI=acos(-1.0);

int dbcmp(double x){
    if(fabs(x)<eps)
        return 0;
    return x<0?-1:1;
}

struct Point{
    double x,y;
    Point(){}
    Point(double _x,double _y){
        x=_x;
        y=_y;
    }
    bool operator == (Point b)const{
        return dbcmp(x-b.x)==0&&dbcmp(y-b.y)==0;
    }
    Point operator -(const Point &b)const{ //叉积
        return Point(x-b.x,y-b.y);
    }
    double operator ^(const Point &b)const{ //点积
        return x*b.y-y*b.x;
    }
    double operator *(const Point &b)const{
        return x*b.x+y*b.y;
    }
    Point operator +(const Point &b)const{
        return Point(x+b.x,y+b.y);
    }
    Point operator *(const double &k)const{
        return Point(x*k,y*k);
    }
    Point operator /(const double &k)const{
        return Point(x/k,y/k);
    }
    double distance(Point p){
        return hypot(x-p.x,y-p.y);
    }
    Point Rotate(double rad){ //逆时针旋转
        return Point(x*cos(rad)-y*sin(rad),x*sin(rad)+y*cos(rad));
    }
};

struct Line{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e){
        s=_s;
        e=_e;
    }
    
    bool pointonseg(Point p){
        return dbcmp((p-s)^(e-s))==0&&dbcmp((p-s)*(p-e))<=0;
    }
    
    double getDistance(Point A){ //点到直线的距离
        return fabs((A-s)^(A-e)/s.distance(e));
    }
    
    Point crosspoint(Line v){
        double a1=(v.e-v.s)^(s-v.s);
        double a2=(v.e-v.s)^(e-v.s);
        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }
};

const double sq3=sqrt(3);

double L,x,y,vx,vy,h;
int k;
Point A,B,C,oripot,v1,v2,v3;
Line AB,AC,BC;

bool check(double tim)
{
    ll kk=0;
    double dis;
    
    dis=BC.getDistance(oripot)+v1.y*tim; //第一种坐标系对应边BC,计算出起点高度+y轴经过距离Δy
    if(dis<0)
        kk+=(ll)((-dis)/h)+1; //如果方向为负方向,计算结果与直接整除略有不同
    else
        kk+=(ll)(dis/h); //正方向正常整除
    
    dis=AC.getDistance(oripot)+v2.y*tim; //第一种坐标系对应边AC,计算出起点高度+y轴经过距离Δy
    if(dis<0)
        kk+=(ll)((-dis)/h)+1;
    else
        kk+=(ll)(dis/h);
    
    dis=AB.getDistance(oripot)+v3.y*tim; //第一种坐标系对应边AB,计算出起点高度+y轴经过距离Δy
    if(dis<0)
        kk+=(ll)((-dis)/h)+1;
    else
        kk+=(ll)(dis/h);
    
    return kk>=k; //最后判断当前的交点个数是否大于等于要求的个数
}

void solve()
{
    cin>>L>>x>>y>>vx>>vy>>k;
    
    h=sq3*L/2.0; //三角形高度
    
    v1=Point(vx,vy); //第一种坐标系下的速度向量
    v2=v1.Rotate(PI*2.0/3); //第二种坐标系下的速度向量(逆时针旋转120°)
    v3=v1.Rotate(-PI*2.0/3);  //第三种坐标系下的速度向量(顺时针旋转120°)
    
    oripot=Point(x,y); //小球初始位置
    A=Point(0,h); //三角形上角
    B=Point(L/2.0,0); //三角形右角
    C=Point(-L/2.0,0); //三角形左角
    
    AB=Line(A,B); //三条边组成的线
    AC=Line(A,C);
    BC=Line(B,C);
    
    double l=0,r=1e10,mid; //二分时间,计算交点个数是否符合条件
    while(r-l>=1e-5) //题目不卡精度,实测1e-4也能过
    {
        mid=(l+r)/2.0;
        if(check(mid))
            r=mid;
        else
            l=mid;
    }
    cout<<r<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cout<<fixed<<setprecision(8);
    int T;cin>>T;
    for(int t=1;t<=T;t++)
        solve();
    return 0;
}

1009 Parentheses Matching

题意

给定一个括号序列,其中仅包含()*,任务就是替换其中的*()或者空字符串,是的原字符串平衡且字典序最小。

解法

括号匹配,注意多个方面的思考,先将正常的括号入栈,如果左括号少,那就将最前面的星号边成左括号,如果最后还有多余的左括号,那就将最后面的星号变成右括号

代码

#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(0), cin.tie(0)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int inf = ~0u >> 1;
typedef pair<int, int> P;
#define REP(i, a, n) for (int i = a; i < (n); ++i)
#define PER(i, a, n) for (int i = (n)-1; i >= a; --i)
char p[maxn];
int ans[maxn];
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%s", p);
        int n = strlen(p);
        //cout << "p =" << p << endl;
        int sum = 0;
        stack<int> s;
        bool flag = true;
        queue<int> xh;
        REP(i, 0, n) {
            ans[i] = 0;
            if (p[i] == '(') {
                s.push(i);
            } else if (p[i] == ')') {
                //cout << s.size() << endl;
                if (!s.empty()) {
                    ans[s.top()] = 1;
                    //cout << "top = " << s.top().second << endl;
                    ans[i] = 2;
                    s.pop();
                } else {
                    if (i > 0 && sum > 0) {
                        ans[i] = 2;
                        ans[xh.front()] = 1;
                        sum--;
                        xh.pop();
                    } else {
                        flag = false;
                        break;
                    }
                }
            } else {
                xh.push(i);
                sum++;
            }
        }
        if (!flag) {
            printf("No solution!\n");
            continue;
        }
        int sum2 = 0;
        queue<int> xh2;
        PER(i, 0, n) {
            if (p[i] == '*') {
                sum2++;
                xh2.push(i);
            }
            //cout << "i = " << i << " p = " << p << " ans = " << ans <<endl;
            if (p[i] == '(' && ans[i] == 0) {
                if (sum2 > 0) {
                    ans[xh2.front()] = 2;
                    ans[i] = 1;
                    xh2.pop();
                    sum2--;
                } else {
                    flag = false;
                    break;
                }
            }
        }
        if (!flag) {
            printf("No solution!\n");
            continue;
        }
        REP(i, 0, n) {
            if (ans[i] == 1) {
                printf("(");
            } else if (ans[i] == 2) {
                printf(")");
            } else if (ans[i] == 0){
                printf("");
            }
        }
        printf("\n");
    }
    return 0;
}

posted @ 2020-08-09 22:13  cugbacm03  阅读(155)  评论(0)    收藏  举报