EZ 2018 05 20 NOIP2018 模擬賽(十五)
這次的比賽充滿著玄學的氣息
首先講一下為什麽沒有第十四場
其實今天早上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 模擬賽(十五)