2018 Multi-University Training Contest 1 部分簡單題解析

Preface

ACM系列賽第一站,沒有進前200仍是很傷的。git

主要是T2當時沒寫出來就GG了,後來看了下其實不是很難。post

題目按照比賽時咱們A的順序講,其實我都是被陳瀟然大佬和ZWC帶飛的。spa


T1 Maximum Multiple

題目大意:給出一個數字\(n\),求三個數\(x,y,z\)知足\(x,y,z|n\)\(x+y+z=n\)。找出這樣一組並使得\(xyz\)最大。有解就輸出\(xyz\)的最大值,不然輸出\(-1\)code

大力猜結論,而後用ZWC當時寫的一個暴力拍了下\(n\le200\)的狀況發現沒問題,而後就交了並1A了。排序

因此ACM猜結論成爲咱們隊的平常ip

如下爲看起來頗有道理的結論:get

  • \(3|n\)時,此時很顯然,答案爲\((\frac{3}{n})^3\)
  • \(4|n\)時,通過一番簡單的推導,獲得答案爲\((\frac{4}{n})^2\cdot \frac{n}{2}\)
  • 其餘狀況一概無解

CODE數學

#include<cstdio>
#include<cctype>
using namespace std;
int n,t;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(long long x)
{
    if (x>9) write(x/10);
    putchar(x%10+'0'); 
}
int main()
{
    //freopen("1.in","r",stdin); freopen("1.out","w",stdout);
    register int i,j; read(t);
    while (t--)
    {
        read(n); 
        if (n%3==0) write(1LL*(n/3)*(n/3)*(n/3)),putchar('\n'); else
        if (n%4==0) write(1LL*(n/4)*(n/4)*(n/2)),putchar('\n'); else puts("-1");
    }
    return 0;
}

T3 Triangle Partition

這題我寫的,感受比T1簡單。string

題目大意:在平面內有保證三點不共線\(3n\)個點,讓你給出一種構造方案組成\(n\)個三角形,使得每一個三角形互不相交it

這個數學老師上課好像講過,咱們把三角形按\(x\)座標排個序,而後每次三個三個取便可。這樣顯然不會相交。

CODE

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int N=1005;
struct data
{
    int x,y,id;
}a[N*3];
int t,n;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; int flag=1; while (!isdigit(ch=tc())) flag=ch^'-'?1:-1;
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); x*=flag;
}
inline void write(int x)
{
    if (x>9) write(x/10);
    putchar(x%10+'0'); 
}
inline bool cmp(data a,data b)
{
    return a.x<b.x;
}
int main()
{
    //freopen("3.in","r",stdin); freopen("3.out","w",stdout);
    register int i; read(t);
    while (t--)
    {
        for (read(n),i=1;i<=3*n;++i)
        read(a[i].x),read(a[i].y),a[i].id=i;
        sort(a+1,a+3*n+1,cmp);
        for (i=1;i<=3*n;i+=3)
        write(a[i].id),putchar(' '),write(a[i+1].id),putchar(' '),write(a[i+2].id),putchar('\n');
    }
    return 0;
}

T11 Time Zone

仍是我寫的,因此WA了幾發。不過之後這種大力模擬題都是陳瀟然大佬寫的了。

題目大意:給出當前的時間(UTC +8)以及目標時區。讓你求目標時區的時間。

大力模擬,有一些細節要注意:

  1. 讀入的時區多是負數或小數
  2. 處理跨度一天的時間是格外要注意一些詭異的狀況

CODE

#include<cstdio>
using namespace std;
int t,a,b,x,y; char ch;
int main()
{
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&a,&b); ch=getchar(); while (ch!='+'&&ch!='-') ch=getchar(); 
        scanf("%d",&x); y=0; if (getchar()=='.') scanf("%d",&y);
        if (ch=='+')
        {
            x-=8; b+=y*6; if (b>59) b-=60,++a; if (b<0) b+=60,--a; a+=x; if (a>23) a-=24; if (a<0) a+=24;
        } else
        {
            x+=8; b-=y*6; if (b<0) b+=60,--a; if (b>59) b-=60,++a; a-=x; if (a<0) a+=24; if (a>23) a-=24;
        }
        if (a>9) printf("%d:",a); else printf("0%d:",a);
        if (b>9) printf("%d\n",b); else printf("0%d\n",b);
    }
    return 0;
}

T4 Distinct Values

這題是ZWC寫的,我已經在YY線段樹上二分的時候他說他用set艹過了此題。

一臉震驚,不過若是你看到下一場我用分塊爆艹線段樹就知道ACM的數據是極水的

題目大意:給你一個長度爲\(n\)的序列以及\(m\)個限制條件,讓你求一個字典序最小的序列知足對於每個限制\(,i,j\in [l_i,r_i],i\not =j\)的一對\(i,j\)都有\(a_i\not = a_j\)

首先把操做按左端點排個序,而後考慮既然是字典序最小,那麼貪心的想每一次確定是把小數字的先放了。

考慮直接用set來維護一下當前能夠被選擇的數,那麼咱們在一個區間退出時能夠直接把它從set裏刪掉,同時在右邊更新的時候把當前這個數插進去便可,取得時候也是貪心地取set裏的最小值。

CODE(ZWC寫的,我懶得再寫一遍了)

#include<cstdio>
#include<algorithm>
#include<set>
#define maxn 100005
using namespace std;
set<int> s;
int T,n,m,ans[maxn];
struct chi{
    int l,r;
    bool operator <(const chi b)const{return l<b.l||(l==b.l&&r>b.r);}
}a[maxn];
int read(){
    int ret=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
    while(ch>='0'&&ch<='9') {ret=ret*10+ch-'0';ch=getchar();}
    return ret*f;
}
int main(){
    T=read();
    while(T--){
        s.clear();
        n=read();m=read();
        for(int i=1;i<=n;i++) s.insert(i),ans[i]=1;
        for(int i=1;i<=m;i++) a[i].l=read(),a[i].r=read();
        sort(a+1,a+1+m);
        int lst=0;a[0].l=1;
        for(int i=1;i<=m;i++){
            if(a[i].r<=a[lst].r) continue;
            for(int j=a[lst].l;j<a[i].l;j++) s.insert(ans[j]);
            for(int j=max(a[lst].r+1,a[i].l);j<=a[i].r;j++) ans[j]=*s.begin(),s.erase(s.begin());
            lst=i;
        }
        for(int i=1;i<=n;i++) printf("%d%c",ans[i],n==i?'\n':' ');
    } 
    return 0;
}

T2 Balanced Sequence

這題以後作的,打的時候抽了沒想出排序的cmp就GG了

題目大意:給出你\(n\)括號序列,讓你用合理的方法把這\(n\)個序列排好順序後使得它們連在一塊兒組成的序列中匹配的左右括號對數最多。

首先考慮先把每個序列中已經含有的對數先算出來,這個很簡單吧,拿棧或者直接開一個變量模擬一下就完了,這些對數能夠直接累加到答案中。

考慮將已經計算完的括號對刪去,那麼剩下的必定是\(')'\cdot x+'('\cdot y\)這樣的形式。

首先咱們考慮全局的貪心,對於那些\(x_i>y_i\)的括號確定得先放在後面,一樣的\(x_i<=y_i\)的就應該儘可能的往前放。

如今咱們考慮局部的貪心若是兩個序列\(i,j\)都是\(x_i>y_i\)的形式,那麼爲了不浪費,咱們確定是把\(x_i\)小的放在前面。

同理,若兩個序列\(i,j\)都是\(x_i<=y_i\)的形式,就要把\(y_i\)小的放在前面。

這樣咱們只要寫好cmp而後在模擬一遍就行了。

CODE

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100005;
struct data
{
    int l,r;
}a[N]; char s[N]; int n,ans,len,res,t;
inline bool cmp(data a,data b)
{
    if (a.l>a.r&&b.l<=b.r) return 1;
    if (a.l<=a.r&&b.l>b.r) return 0;
    if (a.l>a.r&&b.l>b.r) return a.r<b.r;
    return a.l>b.l;
}
inline int min(int a,int b)
{
    return a<b?a:b;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    for (scanf("%d",&t);t;--t)
    {
        register int i,j; ans=res=0;
        for (scanf("%d",&n),i=1;i<=n;++i)
        {
            scanf("%s",s+1); len=strlen(s+1); a[i].l=a[i].r=0;
            for (j=1;j<=len;++j) if (s[j]=='(') ++a[i].l;
            else if (a[i].l) ++ans,--a[i].l; else ++a[i].r;
        }
        for (sort(a+1,a+n+1,cmp),i=1;i<=n;++i)
        {
            int p=min(res,a[i].r); ans+=p;
            res-=p; res+=a[i].l;
        }
        printf("%d\n",ans<<1);
    }
    return 0;
}

Postscript

此次題目整體偏簡單,然而咱們仍是不會作

看來之後這種像T2這樣的中等題要爭取切掉。

相關文章
相關標籤/搜索