2018.8.25 练习赛
- T1 试卷
- 题面:
试卷(paper .cpp/.in/.out) 1s 512MB
题目描述
THH为了回答SF之间,决定在之后的m天中刷很多理综卷子,于是他收集到了 n套理综试卷,每套试卷鄒是不同的。
为了体现概率的根本性,THH 决定随机选择一一个刷题方案,但是为了不让自己某一天太过无聊,他要求每天至少要刷一套试卷,同时为了不让自己过度劳累,他决定这n套题不需要全部刷完。THH当然想知道,总共有多少种可能的刷题方案。
THH当然知道答案,但是他希望你帮他验证一下,由于THH可能会刷很多题,所以你只需要算出答案对p取模后的结果就行了。
输入格式
第一行三个整数id,T,p,分别表示测试点编号,数据组数,模数
接下来T行,每行三个整数n,m,表示一组数据
输出格式
输出T行,每行一个整数ans,分别表示每组数据的答案对p取模的结果
样例输入1
998244353
76
2464 22902603 421
2603 421
样例输出1
1
7
213358738
919699705
数据范围
本题采用打包测试,你只有通过一一个子任务的所有测试点才能获得该子任务对应的分数
对于所有数据,保证m≤n,1≤id≤7
子任务1 (20分):T≤10^5,n≤5000, m<= 5000,p = 998244353, id= 1
子任务2(25分):T≤10^5,n≤10^7,m≤10^7 ,p= 998244353, id= 2
子任务3(15分):T≤10^5,n≤10^15,m≤10^15,p=19999,id= 3
子任务4(15分):T≤3x10^6,n≤10^7,m≤10^7,p=3,id= 4
子任务5(10分):T≤10,n≤10^5,m≤10^15,p= 877368967,id= 5
子任务6(5分) :T≤2x10^3,n≤10^5,m≤10^l5,p= 536078816,id= 6
子任务7(10分):T=30,n≤10^9,m≤10^9,p= 100000007, id= 7
- 名副其实的毒瘤题,七个子任务使用不同的解法:
- 1、暴力O(n^2)即可
- 2、线性求逆元+预处理阶乘
- 3、Lucas
- 4、计算阶乘时将3的倍数提出,然后暴力计算
- 5、CRT
- 6、扩展Lucas
- 7、打表,预处理k,2*k……然后用最近的阶乘进行计算
- code待补
- T2 果实
- 题面:
果实(fruit.cpp/.in/.out) 1s 32MB
题日描述
THH解决了SF之间后决定大宴宾客,于是他找到了一棵有n个节点的果树,这棵果树上总共有C种不同的果k,树上每个节点都 有一一颗果实。
现在THH为了表明自己很文明,决定只在果树上选择一-棵子树摘走,同时,他希望摘到尽可能多的种类的果实,现在THH希望 你能帮助他确定某些子树中总共有多少种不同的果实。
THH总共会有m次询问,为了方便,THH指定了根为1号节点。
输入格式
第一行三个整数n,m,C,意义如题所述
第二行n个整数ay,表示每个节点上果实的种类
接下来n-1行,每行两个整数cy,表示果树上的一一条边
接下来m行,每行一个整数p,表示THH询问以p为根的子树中总共有多少种不同的果实
输出格式
输出m行,每行一个整数ans,表示每个询问的答案
样例输入1
6 3 5
1 2 3 4 5 1
5 1
1 3
3 4
4 2
3 6
1
4
6
样例输出1
5
2
1
数据范围
本题采用打包测试,你只有通过一一个子任务的所有测试点才能获得该子任务对应的分数
对于所有数据,保证n,m,C≤10^5,1≤a;≤C
予任务1(20分) :n≤5000,m≤5000,C≤105
子任务2(30分):n≤10^5,m≤10^5,C≤60
子任务3(10分):n≤10^5,m≤10^5,C≤10^5,保证树的形态为一条链
子任务4(40分):n≤5x10^5,m≤5x10^5,C≤5x10^5
- 正解是dfs序将子树问题转化为区间问题树状数组维护树上查分;但是用莫队莫名其妙就玄学卡过了……
- 莫队代码:
-
1 #include<stdio.h> 2 #include<math.h> 3 #include<ctype.h> 4 #include<vector> 5 #include<algorithm> 6 using namespace std; 7 8 char buf[1<<20],*p1,*p2; 9 inline char gc() { 10 return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++; 11 } 12 13 template<typename T> 14 void read(T &x) { 15 char tt; 16 bool flag=0; 17 while(!isdigit(tt=gc())&&tt!='-'); 18 tt=='-'?(x=0,flag=1):(x=tt-'0'); 19 while(isdigit(tt=gc())) x=x*10+tt-'0'; 20 if(flag) x=-x; 21 } 22 23 template<typename T> 24 void write(T x,bool flag) 25 { 26 if(x<0) putchar('-'),x=-x; 27 if(!flag) putchar(x%10+'0'); 28 if(x>9) write(x/10),putchar(x%10+'0'); 29 } 30 31 struct node { 32 int l,r,id; 33 } q[500005]; 34 35 int n,m,c; 36 vector<int>G[500005]; 37 int dfn[500005],pos[500005][2],tot; 38 int tmp[500005],block[500005],s,Ans,l=1,r; 39 int d[500005]; 40 int a[500005],ans[500005]; 41 42 bool cmp(node a,node b) { 43 return block[a.l]==block[b.l]?a.r<b.r:a.l<b.l; 44 } 45 46 void modify(int x,int k) { 47 d[x]+=k; 48 if(k>0) Ans+=d[x]==1; 49 if(k<0) Ans-=d[x]==0; 50 } 51 52 void dfs(int x,int pre) { 53 dfn[++tot]=x; 54 pos[x][0]=tot; 55 for(int i=0,p=G[x][i]; i<G[x].size(); i++,p=G[x][i]) 56 if(p!=pre) dfs(p,x); 57 pos[x][1]=tot; 58 } 59 60 int main() { 61 scanf("%d%d%d",&n,&m,&c); 62 for(int i=1; i<=n; i++) scanf("%d",&tmp[i]); 63 for(int i=1; i<n; i++) { 64 int x,y; 65 scanf("%d%d",&x,&y); 66 G[x].push_back(y); 67 G[y].push_back(x); 68 } 69 dfs(1,0); 70 s=pow(tot,0.6666); 71 for(int i=1; i<=m; i++) { 72 int x; 73 scanf("%d",&x); 74 q[i]=(node) { 75 pos[x][0],pos[x][1],i 76 }; 77 block[i]=(i-1)/s+1; 78 } 79 for(int i=1; i<=n; i++) a[i]=tmp[dfn[i]]; 80 sort(q+1,q+1+m,cmp); 81 for(int i=1; i<=m; i++) { 82 while(l<q[i].l) modify(a[l],-1),l++; 83 while(l>q[i].l) modify(a[l-1],1),l--; 84 while(r<q[i].r) modify(a[r+1],1),r++; 85 while(r>q[i].r) modify(a[r],-1),r--; 86 87 ans[q[i].id]=Ans; 88 } 89 for(int i=1; i<=m; i++) 90 printf("%d\n",ans[i]); 91 }
- T3 旅行
- 题面:
旅行(travel.cpp/.in/.out) 1s 32MB
题目描述
心情大好的THH决定出去旅行,他决定在n个城市中米选择旅行路线,这n个城市由m条双向道路连接,由于特殊的原因,对于 双向道路(r,y),→y的长度为c,y→x的长度为di,THH居住的城市为1号城市。
现在THH想要从1号城市出发,经过一些城市,最后回到1号城市,并且由于每条路上的风景是一样的,因此THH要求每条边至 多经过一次,然而TH H发现旅行可能会耗费过多时间,于是他决定在所有的可能路线中选择最短的那一. 条路线。
由于THH正忙于收拾书包,所以他拜托你帮他计算一-下最短的可能路线的长度。
输入格式
第一行两个整数n,m,意义如题所述
接下来m行,每行三个整数正, Yi,Gi,d;,表示一条道路
输出格式
输出一行,一个整数ans,表示答案
样例输入1
5 7
1 2 3 2
1 3 3 3
2 4 1 2
2 5 7 8
4 5 2 2
3 5 3 4
3 4 8 7
样例输出1
12
数据范围
本题采用打包测试,你只有通过一一个子任务的所有测试点才能获得该子任务对应的分数对于所有数据,保证n≤5x 10^4,m≤5x 10^5,0≤d;≤10^4,保证图中不存在重边和自环,保证一定有解
子任务1 (20分):n≤20,m≤100
子任务2(30分) :n≤1500,m < 15000
子任务3(50分):n≤5x 10^5,m≤2x10^5
- 正解为迪杰斯特拉,将一号点分为两组,一组只有出,一组只有入,随机化跑30次,错误几率为(3/4)^30,或者用二进制分组
- 二进制分组code:
-
1 #include<stdio.h> 2 #include<vector> 3 #include<queue> 4 #include<algorithm> 5 #define ll long long 6 #define inf 2138127381723192LL 7 using namespace std; 8 9 struct node { 10 ll v,len; 11 bool operator<(node a) const { 12 return len>a.len; 13 } 14 }; 15 16 ll n,m,ans=inf; 17 vector<node>G[50005]; 18 priority_queue<node>q; 19 ll dis[50005]; 20 21 ll solve(ll lim,ll t) { 22 for (int i=0; i<=n; i++) dis[i]=inf; 23 dis[1]=0,q.push((node) {1,0}); 24 while(!q.empty()) { 25 node p =q.top(); 26 q.pop(); 27 if(p.len!=dis[p.v]) continue; 28 for(int i=G[p.v].size()-1; i>=0; i--) { 29 node v=G[p.v][i]; 30 if (p.v==1&&v.v>>lim&1^t) continue; 31 if (v.v==0&&p.v>>lim&1^t^1) continue; 32 if (dis[v.v]<=dis[p.v]+v.len) continue; 33 q.push((node) {v.v,dis[v.v]=dis[p.v]+v.len}); 34 } 35 } 36 return dis[0]; 37 } 38 39 int main() { 40 scanf("%lld%lld",&n,&m); 41 for(int i=1; i<=m; i++) { 42 ll x,y,k,d; 43 scanf("%lld%lld%lld%lld",&x,&y,&k,&d); 44 if(x>y) swap(x,y),swap(d,k); 45 G[x].push_back((node) {y,k}); 46 if(x==1) x=0; 47 G[y].push_back((node) {x,d}); 48 } 49 ll tmp=n,tot=0; 50 while(tmp) tot++,tmp>>=1; 51 for(int i=0; i<tot; i++) ans=min(ans,min(solve(i,0),solve(i,1))); 52 printf("%lld",ans); 53 }