1. 程式人生 > >EZ 2018 05 20 NOIP2018 模擬賽(十五)

EZ 2018 05 20 NOIP2018 模擬賽(十五)

html cst PE com space 相對 stdin 順序 處理

這次的比賽充滿著玄學的氣息

首先講一下為什麽沒有第十四場

其實今天早上9點時看到題目就叫了:原題!

沒錯,整套試卷都做過,我還寫了題解

然後老葉就說換一套,但如果僅僅是這樣就沒什麽

但等13min後結束這場考試後,一評測發現有人A了T1

但老葉並沒有開啟Unrated,然後大家集體墊底被踩

然後我就莫名掉了74Rating

但是之後第二場很快就開始了,但是等第二場測完之後還是沒有進行Unrated處理,結果就白掉分了

真是Dog至極

然後講一下題目,這次主要是T2炸了,花了蠻長時間寫O(n^2)的玄學的,然後所有數據點中竟沒有一個點的n小於5000(全是90000+)

但是T3莫名快速冪多得了40pts還是很令人欣慰的

T1

這道題無疑是本場最不可做的一道題

具體的滿分算法需要二維樹狀數組 or 主席樹來搞

這裏就直接優化一下暴力得50pts就很優秀

由於本題數據n的範圍不大,可以直接埃式篩來搞

50CODE

#include<cstdio>
using namespace std;
const int N=100005,MAX_SIZE=1000005;
int a[N],n,q,l[N],r[N],x[N],y[N],max_num;
bool prime[MAX_SIZE];
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=tc();
    while (ch<‘0‘||ch>‘9‘) ch=tc();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=tc();
}
inline void write(long long x)
{
    if (x/10) write(x/10);
    putchar(x%10+‘0‘);
}
inline int max(int a,int b)
{
    return a>b?a:b;
}
inline void get_prime(int m)
{
    register int i,j;
    for (prime[1]=1,i=2;i<=m;++i)
    if (!prime[i]) for (j=i<<1;j<=m;j+=i) prime[j]=1;
}
inline long long work(int l,int r,int x,int y)
{
    long long tot=0; register int i,j;
    for (i=x;i<=y;++i)
    if (!prime[i])
    for (j=l;j<=r;++j)
    {
        int now=a[j];
        while (!(now%i)) ++tot,now/=i;
    }
    return tot;
}
int main()
{
    //freopen("A.in","r",stdin); freopen("A.out","w",stdout);
    register int i;
    for (read(n),i=1;i<=n;++i)
    read(a[i]);
    for (read(q),i=1;i<=q;++i)
    read(l[i]),read(r[i]),read(x[i]),read(y[i]),max_num=max(max_num,y[i]);
    get_prime(max_num);
    for (i=1;i<=q;++i)
    write(work(l[i],r[i],x[i],y[i])),putchar(‘\n‘);
    return 0;
}

T2

這其實時一道比較經典的水題

我們先考慮在一條直線上的情況,就是Luogu P1367

假設兩只螞蟻A,B面對面相遇:

/Here is Pic 1

然後他們掉頭,相當於穿過了對方並且互換身份

/Here is Pic 2

但是這裏有一個很重要的性質:它們的相對位置不會改變

什麽意思——就是不管它們怎麽移動,第i只螞蟻的左邊一定是第i-1只螞蟻,右邊一定是第i+1只螞蟻

然後只要sort一下就可以了

但是對於這道題是一個圓的情況,則有些在後面的螞蟻可能會排到前面去

但是螞蟻的位置還是不變,並且相對位置保持相對不變,因此我們只要知道第1只螞蟻的位置就可以順次求出後面螞蟻的位置

我們設第一只螞蟻的相對排名為cnt,初始值為1.每當一只螞蟻從l-1到達0時,cnt++;每當一只螞蟻從0爬到l-1時,cnt--

然後就排序後通過cnt正確輸出順序即可

因為當前HHHOJ沒有開放這次題目,因此到Atcoder提交即可

CODE

#include<cstdio>
#include<algorithm>
const int N=1e5+5;
int a[N],n,l,t,x,w;
long long cnt=1;
using namespace std;
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=tc();
    while (ch<‘0‘||ch>‘9‘) ch=tc();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=tc();
}
inline void write(int x)
{
    if (x/10) write(x/10);
    putchar(x%10+‘0‘);
}
int main()
{
    //freopen("B.in","r",stdin); freopen("B.out","w",stdout);
    register int i;
    read(n); read(l); read(t);
    for (i=1;i<=n;++i)
    {
        read(x); read(w);
        if (w==1) a[i]=(x+t)%l,cnt+=(x+t)/l; else a[i]=(x-t%l+l)%l,cnt-=t%l>x?t/l+1:t/l;
    }
    cnt=(cnt%n+n-1)%n+1;
    sort(a+1,a+n+1);
    for (i=cnt;i<=n;++i)
    write(a[i]),putchar(‘\n‘);
    for (i=1;i<cnt;++i)
    write(a[i]),putchar(‘\n‘);
    return 0;
}

T3

首先30pts的爆搜不講

然後這題有一個性質:若n>=m,即ans為2^2m,因為就有所有的塔都有可能紅或藍

快速冪求之即可,結合爆搜可以得70pts

考慮DP,這裏用r表示紅的,b表示藍的

我們首先發現,每一次操作的時候加上去的要麽是"rr","rb","br","bb",而且手上紅色藍色的和總是為n

而且條件很簡單,若第一位r則此時手上必須有1個r

然後我們設f[i][j]表示進行第i次操作時手上有j個紅色的方案總數,則藍的有n-j個

又發現這樣可能會用重復的方案,然後我們發現:**若對於兩種狀態,手上的紅色個數不為0,那麽它們就重復了

因此我們設f[i][j][0/1]表示此時紅色的是否取完過,然後再轉移即可

Atcoder鏈接

CODE

#include<cstdio>
#include<cstring>
using namespace std;
const int N=3005,mod=1e9+7;
int f[2][N][2],n,m,ans;
inline void inc(int &x,int y)
{
    x+=y; x-=x>=mod?mod:0;
}
int main()
{
    register int i,j,k;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;++i)
    f[0][i][0]=1; f[0][0][1]=1;
    for (i=0;i<m;++i)
    {
        int now=i&1,nxt=now^1;
        memset(f[nxt],0,sizeof(f[nxt]));
        for (j=0;j<=n;++j)
        for (k=0;k<=1;++k)
        {
            if (j) inc(f[nxt][j-1][k|(j==1)],f[now][j][k]);
            if (j) inc(f[nxt][j][k|(j==1)],f[now][j][k]);
            if (n-j) inc(f[nxt][j+1][k],f[now][j][k]);
            if (n-j) inc(f[nxt][j][k],f[now][j][k]);
        }
    }
    for (i=0;i<=n;++i)
    inc(ans,f[m&1][i][1]);
    printf("%d",ans);
    return 0;
}

EZ 2018 05 20 NOIP2018 模擬賽(十五)