10.28模擬賽
幸運數字(number)
Description
LYK 最近運氣很差,例如在 NOIP 初賽中僅僅考了 90 分,剛剛卡進復賽,於是它決定使 用一些方法來增加自己的運氣值。
它覺得,通過收集幸運數字可以快速的增加它的 RP 值。
它給幸運數字下了一個定義:如果一個數 x 能被 3 整除或被 5 整除或被 7 整除,則這個 數為幸運數字。
於是它想讓你幫幫它在 L~R 中存在多少幸運數字
Input
第一行兩個數 L,R。
Output
一個數表示答案 。
數據範圍
對於 50%的數據 1<=L<=R<=10^5。
對於 60%的數據 1<=L<=R<=10^9。
對於 80%的數據 1<=L<=R<=10^18。
對於 90%的數據 1<=L<=R<=10^100。
對於另外 10%的數據 L=1, 1<=R<=10^100。
對於 100%的數據 L, R 沒有前導 0。
哇,水題.
很明顯是容斥原理.
\(L\)到\(R\)的答案可以化簡為\(1\)到\(R\)的答案減去\(1\)到\(L-1\)的答案.(貌似這也是容斥)
所以根據容斥原理的式子(這裏就不放了)。
最終推得式子為
\[
A=\frac{R}{3}+\frac{R}{5}+\frac{R}{7}-\frac{R}{15}-\frac{R}{21}-\frac{R}{35}+\frac{R}{105}
\]
\[ B=\frac{L-1}{3}+\frac{L-1}{5}+\frac{L-1}{7}-\frac{L-1}{15}-\frac{L-1}{21}-\frac{L-1}{35}+\frac{L-1}{105} \]
\[ ans=A-B \]
但是看到數據範圍你不慌嘛?
高精?完了要涼
硬著頭皮碼(tiao)了1個半小時.
問題不大.
代碼
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define clear(a) memset(a,0,sizeof a) #define N 10008 #define R register using namespace std; int len,a[N],b[N],t[N],ans[N]; int sa[N],sb[N],c[2]={1,1}; char l[N],r[N]; inline void pre(int *a,int *b) { clear(sa);clear(sb); sa[0]=a[0]; for(int i=1;i<=a[0];i++) sa[i]=a[a[0]-i+1]; for(int i=1;i<=b[0];i++) sb[i]=b[b[0]-i+1]; for(R int i=1;i<=sa[0];i++) { sa[i]-=sb[i]; if(sa[i]<0) { sa[i]+=10; sa[i+1]--; } } while(sa[0]>1 and sa[a[0]]==0)sa[0]--; a[0]=sa[0]; for(int i=1;i<=sa[0];i++)a[i]=sa[sa[0]-i+1]; } inline void div(int *a,int *b,int x) { int plus=0; a[0]=b[0]; for(R int i=1;i<=b[0];i++) { plus=plus*10+b[i]; a[i]=plus/x;plus%=x; } } inline void add(int *a,int *b) { clear(sa),clear(sb); int len1=a[0],len2=b[0],len=1; for(R int i=1;i<=len2;i++) sb[i]=b[len2-i+1]; for(;len<=len1 or len<=len2;len++) { sa[len]+=a[len]+sb[len]; sa[len+1]=sa[len]/10; sa[len]=sa[len]%10; } while(len>1 and sa[len]==0)len--; sa[0]=len; for(R int i=0;i<=sa[0];i++)a[i]=sa[i]; } inline void jian(int *a,int *b) { clear(sb); for(R int i=1;i<=b[0];i++) sb[i]=b[b[0]-i+1]; for(R int i=1;i<=a[0];i++) { a[i]=a[i]-sb[i]; if(a[i]<0) { a[i]=a[i]+10; a[i+1]--; } } while(a[0]>1 and a[a[0]]==0)a[0]--; } int main() { freopen("number.in","r",stdin); freopen("number.out","w",stdout); scanf("%s",l); scanf("%s",r); int len1=strlen(l),len2=strlen(r); a[0]=len1,b[0]=len2; for(int i=1;i<=len1;i++) a[i]=l[i-1]-'0'; for(int i=1;i<=len2;i++) b[i]=r[i-1]-'0'; pre(a,c); /**/ div(t,b,3);add(ans,t); div(t,b,5);add(ans,t); div(t,b,7);add(ans,t); div(t,a,3);jian(ans,t); div(t,a,5);jian(ans,t); div(t,a,7);jian(ans,t); /**/ /**/ div(t,a,15);add(ans,t); div(t,a,21);add(ans,t); div(t,a,35);add(ans,t); div(t,b,15);jian(ans,t); div(t,b,21);jian(ans,t); div(t,b,35);jian(ans,t); /**/ /**/ div(t,b,105);add(ans,t); div(t,a,105);jian(ans,t); /**/ for(R int i=ans[0];i>=1;i--) printf("%d",ans[i]); fclose(stdin); fclose(stdout); return 0; }
位運算(bit)
Description
lyk 最近在研究位運算。它發現除了 xor,or,and 外還有很多運算。
它新定義了一種運算符“#” 。 具體地,可以由 4 個參數來表示。 令 a[i][j]表示 i#j。 其中 i,j 與 a 的值均∈[0,1]。
當然問題可以擴展為>1 的情況,具體地,可以將兩個數分解為 p 位,然後對於每一位 執行上述的位運算,再將這個二進制串轉化為十進制就可以了。
例如當 a[0][0]=0, a[1][1]=0, a[0][1]=1, a[1][0]=1 時,3#4 在 p=3 時等於 7,2#3 在 p=4 時等於 1(實際上就是異或運算)。
現在 lyk 想知道的是,已知一個長為 n 的數列 b。它任意選取一個序列 c,滿 足 c1<c2<...<ck,其中 1≤c1 且 ck≤n,定義這個序列的價值為 b{c1}#b{c2}#...#b{ck} 的平方。
這裏我們假設 k 是正整數,因此滿足條件的 c 的序列個數一定是 2^n-1 。
lyk 想知道 所有滿足條件的序列的價值總和是多少。
由於答案可能很大, 你只需輸出答案對 1,000,000,007 取模後的結果即可
Input
第一行兩個數 n,p。
第二行 4 個數表示 \(a[0][0], a[0][1], a[1][0], a[1][1]\)。
第三行 n 個數表示 bi(0<=bi<2^p)。
Output
一個數表示答案 。
數據範圍
總共 10 組數據。
對於第 1,2 組數據 n<=5。
對於第 3,4 組數據 n<=10000, p=1。
對於第 5 組數據 a 值均為 0。
對於第 6 組數據 a 值均為 1。
對於第 7 組數據 \(a[0][0]=0,a[1][0]=0,a[1][1]=1,a[0][1]=1\)。
對於第 8,9 組數據 n<=1000, p<=10。
對於所有數據 n<=10000, 1<=p<=30。
對於現在的我來說不可做不可做。
連特判都錯了
\(std\)
將一個數的平方拆成若幹冪次的平方,例如\(7^{2}=(1+2+4)^2\)。
觀察答案的形式為\(1*1+1*2+1*4+2*1+2*2+2*4+4*1+4*2+4*4\)。
枚舉每兩位,令\(dp[i][j][k]\)表示到第i位,此時第一位為j,第二位為k的方案總數,累加即可。
螞蟻運輸(ant)
LYK 在觀察一些螞蟻。
螞蟻想要積攢一些貨物來過冬。
積攢貨物的方法是這樣的。 對於第 i 只螞蟻,它要從 li出發,拿起貨物,走到 ri處放下貨物,需要消耗的時間為|ri-li|。 而且所有螞蟻都是可以同時進行的,也就是說,假如有 m 只螞蟻,那麽運輸完貨物的時間 為 max{|ri-li|}。
LYK 決定幫螞蟻一把,它發明了空間傳輸裝置。具體地,當螞蟻走到 X 處時,它可以不 耗費任意時間的情況下瞬間到達 Y,或者從 Y 到達 X。也就是說,一個螞蟻如果使用了空間 傳輸裝置,它耗費的時間將會是 min{|li-X|+|ri-Y|,|li-Y|+|ri-X|},當然螞蟻也可以選擇徒步走 到目標點。
由於空間傳輸裝置非常昂貴, LYK 打算只建造這麽一臺機器。並且 LYK 想讓螞蟻運輸完 貨物的時間盡可能短,你能幫幫它嗎?
Input
第一行兩個數 n,m, n 表示 li,ri 的最大值。
接下來 m 行,每行兩個數 li,ri。
Output
一個數表示答案 。
數據範圍
對於 20%的數據 n,m<=100。
對於 40%的數據 n,m<=1000。
對於 60%的數據 n<=100000, m<=1000。
對於 80%的數據 n,m<=100000
對於 100%的數據 n,m<=1000000, 1<=li,ri<=n(li=ri 時你甚至可以無視這只螞蟻)。
這套題太惡心了!
尤其是這題.
出題人造數據竟然不說\(l\)可能大於\(r\)!其實是我沒看到中間的逗號
然後由\(100pts\)變成了\(30pts\)!!!
要不\(rank3\)了!
二分答案
讀入時一定要!一定要!保證\(l_i<=r_i\)
\(ok(mid)\)時
設建的傳送站為\(X Y\)
\(abs(l-X)+abs(r-Y)<=mid\)
將\(abs\)拆開,存在四種情況
- \(l-X+r-Y<=mid\)
- \(l-X+Y-r<=mid\)
- \(X-l+r-Y<=mid\)
- \(X-l+Y-r<=mid\)
則存在以下倆不等式.
\(l+r-mid<=X+Y<=l+r+mid\)
\(l-r-mid<=X-Y<=l-r+mid\)
只要存在X,Y對於所有的l,r滿足上面兩條件即可
然後逼近即可.
一定要判斷輸入!!!!!!
\(std\)
觀察到答案具有可二分性。我們可以二分答案。
由於路徑都是無向的,因此對於任意一條方案li,ri若li>ri則可以交換li和ri。
我們設二分的答案為x。
對於那些li+x>=ri的方案我們直接默認為可行。
我們規定X<=Y。
對於li+x<ri的方案。只有一種可能能夠完成,即,從li出發,到達X,到達Y,到達ri。
也就是說,如果X確定,Y存在於一段區間內。
我們來看li>=X的情況。
先求出X=n時符合條件的Y的區間。當X慢慢減少時,這個區間肯定也在慢慢合攏,並且滿足li>=X的條件也會越來越多。我們可以線性求出所有這個區間。
對於li<X的情況也同理。
這樣就能做到線性判斷,總復雜度nlgn。(這裏默認n與m同階)
代碼
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<algorithm>
#define R register
using namespace std;
inline void in(int &x)
{
int f=1;x=0;char s=getchar();
while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
while(isdigit(s)){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,m,cnt;
struct cod{int l,r;}ant[1000008];
inline bool ok(int x)
{
R int le=-2147483644,ri=2147483644;
for(R int i=1;i<=cnt;i++)
{
if(ant[i].r-ant[i].l<=x)continue;
le=max(le,ant[i].l+ant[i].r-x);
ri=min(ri,ant[i].l+ant[i].r+x);
}
if(le>ri)return false;
le=-2147483644,ri=2147483644;
for(R int i=1;i<=cnt;i++)
{
if(ant[i].r-ant[i].l<=x)continue;
le=max(le,ant[i].l-ant[i].r-x);
ri=min(ri,ant[i].l-ant[i].r+x);
}
if(le>ri)return false;
return true;
}
int main()
{
freopen("ant.in","r",stdin);
freopen("ant.out","w",stdout);
in(n),in(m);
{
for(R int i=1,x,y;i<=m;i++)
{
in(x),in(y);
if(x>y)swap(x,y);
ant[++cnt].l=x,ant[cnt].r=y;
}
int l=0,r=1e9,ans;
while(l<=r)
{
int mid=(l+r)>>1;
if(ok(mid))r=mid-1,ans=mid;
else l=mid+1;
}
printf("%d",ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}
10.28模擬賽