7.29NOIP模擬賽
7.29NOIP模擬賽
T1
YSG (1s,64MB,ysg.in,ysg.out)
描述
ysg,yxy,azw 三人正在刷題。
他們每做一題的時間都是一個有理數。
如果在某一時刻,三人同時做完一道 題,那麽,他們會開始談笑風生。
現在,他們想知道,從時刻 0 開始,至少要等多久才能談笑風生。
輸入格式
一行 6 個整數 a1,b1,a2,b2,a3,b3,其中 ysg 每做一道題的時間是 a1/b1,
yxy 是 a2/b2,azw 是 a3/b3。不保證 a,b 互質。
輸出格式
一行 2 個數 c,d,表示第一次談笑風生是在時刻 c/d。其中 c,d 互質。
輸入樣例
3 6 4 5 3 1
輸出樣例
12 1
樣例解釋
在時刻 12,ysg 做了 24 道題,yxy 做了 15 道題,azw 做了 4 道題,他們開始 談笑風生。
備註
對於 30%的數據,b1=b2=b3=1。 對於 100%的數據,a1,a2,a3,b1,b2,b3<=100
題解:
先將三個分數化簡,
再三個分數通分(可以求最小公倍數,也可以分母直接相乘),同時乘以d,
求出通分後的數的最小公倍數c,
c/d化簡一下即為答案
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 int a1,b1,a2,b2,a3,b3; 6 inline int gcd(int x,int y){ 7 if(y>x) swap(x,y); 8 if(y==0) return x; 9 return gcd(y,x%y); 10 } 11 inline void huajian(int &x,int &y){ 12 int g=gcd(x,y); 13 x/=g; y/=g; 14 } 15 inline int get_lcm(int a,int b,int c){ 16 int l1=a*b/gcd(a,b); 17 return l1*c/gcd(l1,c); 18 } 19 int main() 20 { 21 freopen("ysg.in","r",stdin); 22 freopen("ysg.out","w",stdout); 23 scanf("%d%d%d%d%d%d",&a1,&b1,&a2,&b2,&a3,&b3); 24 huajian(a1,b1); 25 huajian(a2,b2); 26 huajian(a3,b3); 27 int lcm1=get_lcm(b1,b2,b3); 28 int lcm2=get_lcm(a1*lcm1/b1,a2*lcm1/b2,a3*lcm1/b3); 29 huajian(lcm1,lcm2); 30 printf("%d %d\n",lcm2,lcm1); 31 fclose(stdin); fclose(stdout); 32 return 0; 33 }
T2
YXY (1s,128MB,yxy.in,yxy.out)
問題描述
ysg,yxy,azw 三人正在刷題。
OJ 上一共有 n 道題,然而因為有的題的算法有人不會,所以他們決定每人做一道題。
現在他們已經分配好了做題任務,把每道題都指定給一個人做
但是如果有 人做的題數量比其他人多,他就會感覺不爽。
為了避免這種情況,他們只好選一些題不做,但是為了美觀,他們做的題目 必須是連續一段。
他們現在想知道,有多少種選擇的方案滿足條件。
輸入格式
輸入數據有 n 行,每行一個字符串,為”ysg”,”yxy”,”azw”中的一個,
第 i 行代 表做第 i 題的人的名字。
輸出格式
輸出有多少種選擇的方案
輸入樣例
ysg
yxy
azw
azw
yxy
azw
yxy
ysg
yxy
ysg
ysg
輸出樣例
3
樣例說明
有三種方案,選 1~3 一段,選 6~8 一段,選 3~11 一段,
每一段內三個名字,出現次數一樣多
數據範圍
對於 20%的數據,n <= 100。
對於 40%的數據,n <= 1000。
對於 100%的數據,n <= 100000
題解:
40pts:
搞三個前綴和數組,分別維護三個名字的出現次數,
O(n^2)查詢,若一段區間內三個名字的出現次數相同,ans++
100pts:
從左到右掃一遍,記錄兩個值:
delta1:以now為結尾的前綴中ysy出現的次數-yxy出現的次數
delta2:以now為結尾的前綴中yxy出現的次數-azw出現的次數
顯然,若在兩個不同的位置l和r,delta1(l)==delta(r)且delta2(l)==delta2(r),
說明從l到r三個名字出現的次數是一樣的,ans++
用map維護即可
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<map>
5 using namespace std;
6 #define N 100000
7 map<int,int> a[N*2+20];
8 int n,d1=N,d2=N,ans;
9 int main()
10 {
11 a[N][N]=1; char s[5];
12 while(scanf("%s",s)!=EOF){
13 if(s[0]==‘y‘)
14 if(s[1]==‘s‘)
15 d1++;
16 else {
17 d1--; d2++;
18 }
19 else d2--;
20 ans+=a[d1][d2];
21 a[d1][d2]++;
22 }
23 printf("%d\n",ans);
24 return 0;
25 }
T3
AZW (2s,256MB,azw.in,azw.out)
問題描述
ysg,yxy,azw 三人正在刷題。
在他們刷題的 oj 上,除第 0 題外,每道題都有一個父親(父親的編號不一定 比他自己小),
所以可以把這些題看成一個樹形的結構。
他們在接下來的 m 天中,每天要麽做一道新題,要麽瀏覽一些題。
瀏覽的方法是:
先選兩道題 x,y,然後把這兩道題之間路徑上的題全部瀏覽一遍。
在瀏覽的時候,他們有時會發現一道題似曾相識,可又想不起何時做過,
原來是他們做這道題的時間太過久遠,以致記憶的模糊。
具體來說,如果一道題做 題時間距離瀏覽的時間已經超過了他們當天的記憶力,
他們就會出現這樣的情況 (具體看樣例)。
所以,現在對於每次瀏覽,他們想知道,這次瀏覽會看多少道題,以及有多少題似曾相識。
輸入格式
第一行一個數 n,代表 oj 上有 n+1 題(從 0 到 n)。
第二行 n 個數,表示第 i 道題的父親的編號。
第三行一個數 m,代表一共 m 天 接下來 m 行,先是一個數 1 或者 2,如果是 1,後面接三個數 x,y,c,表示當 天的瀏覽從 x 到 y,當天記憶力為 c,否則後面接一個數 x,表示當天做了第 x 題
輸出格式
對於每次瀏覽,輸出一行兩個數,表示這次瀏覽會看多少道題,以及有多少 題似曾相識。
輸入樣例
7
0 1 1 2 2 3 3
6
1 4 7 0
2 1
2 4
2 7
1 4 7 1
1 4 7 3
輸出樣例
5 0
5 2
5 1
樣例說明
3 次都是瀏覽 5 道題,分別是 4 號、2 號、1 號、3 號和 7 號。
其中,對於第 1 天,所有題都沒有做過;
對於第 5 天,有 2 道題似曾相識,分別是 1 號和 4 號, 7 號雖然做過,但只隔 1 天,剛好等於記憶力,所以還想得起;
對於第 6 天,只有 1 號似曾相識。
數據範圍
對於 20%的數據,n <= 100,m<=100。
對於 40%的數據,n <= 2000,m<=2000。
另有 20%的數據,沒有做題的操作
另有 20%的數據,雖有做題操作,但每天的記憶力都是 0
對於100%的數據,n <= 200000,m<=200000,保證一道題不會做兩遍
題解:
40pts:dfs暴力在樹上走,每路過一個點就看他是不是之前做過,是在什麽時候做的。
60pts:40+加上求lca,
80pts:60+樹鏈剖分/dfs序,求路徑上有多少做過的題
100pts:就是相當於先把每個點是在什麽時候被做的預處理出來,然後每次詢問一條鏈上面被做時間小於一個給定數的點有多少個,用樹上主席樹。
別人的代碼:
1 #include<cstdio>
2 #include<vector>
3 #include<algorithm>
4 #define N 200011
5 using namespace std;
6
7 int n,m,a1[N],a2[N],a3[N],a4[N];
8 int cc[N],c[20*N][2],z[20*N],t;
9 vector<int>g[N];
10 int s[N],f[20][N],d[N];
11 int lca(int u,int v){
12 if(d[u]<d[v])swap(u,v);
13 for(int i=17;~i;i--)
14 if(1<<i<=d[u]-d[v])
15 u=f[i][u];
16 if(u==v)return u;
17 for(int i=17;~i;i--)
18 if(f[i][u]^f[i][v])
19 u=f[i][u],v=f[i][v];
20 return f[0][u];
21 }
22 int cx(int o,int p){
23 int ans=0;
24 for(int l=1,r=m;l^r;)
25 if(p>l+r>>1)ans+=z[c[o][0]],
26 o=c[o][1],l=(l+r>>1)+1;
27 else o=c[o][0],r=l+r>>1;
28 return ans;
29 }
30 int main(){
31 scanf("%d",&n);
32 t=++n;
33 for(int i=2;i<=n;i++){
34 scanf("%d",&f[0][i]);
35 g[++f[0][i]].push_back(i);
36 }
37 scanf("%d",&m);
38 for(int i=1;i<=n;i++)
39 cc[i]=m;
40 for(int i=1;i<=m;i++){
41 scanf("%d",&a1[i]);
42 if(a1[i]==1)scanf("%d%d%d",&a2[i],&a3[i],&a4[i]),a2[i]++,a3[i]++;
43 else scanf("%d",&a2[i]),cc[++a2[i]]=i;
44 }
45 d[1]=1;
46 for(s[s[0]=1]=1;s[0];){
47 int u=s[s[0]--];
48 z[u]=z[f[0][u]]+1;
49 for(int o=u,oo=f[0][u],l=1,r=m;l^r;){
50 int w=cc[u]>l+r>>1;
51 if(w)l=(l+r>>1)+1;
52 else r=l+r>>1;
53 c[o][w^1]=c[oo][w^1];
54 o=c[o][w]=++t,oo=c[oo][w];
55 z[o]=z[oo]+1;
56 }
57 for(int i=0;i<g[u].size();i++)
58 d[g[u][i]]=d[u]+1,s[++s[0]]=g[u][i];
59 }
60 for(int k=0;1<<k<n;k++)
61 for(int i=1;i<=n;i++)
62 f[k+1][i]=f[k][f[k][i]];
63 for(int i=1;i<=m;i++)
64 if(a1[i]==1){
65 int u=a2[i],v=a3[i],w=lca(u,v),p=i-a4[i];
66 printf("%d %d\n",d[u]+d[v]-2*d[w]+1,cx(u,p)+cx(v,p)-cx(w,p)-cx(f[0][w],p));
67 }
68 }
7.29NOIP模擬賽