1. 程式人生 > 實用技巧 >7.28 2020 Multi-University Training Contest 3題解及補題

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;
}