TZOJ 挑战题库随机训练02

点击题号跳转

原H题不存在,所以只有9题

A5381    B5822    C1157   D5151   E5133
F1369    G4170    H4733   I1147

A.C++实验:STL之search回到顶部

题意

STL中的search函数,判断一个序列是否是另一个序列的子序列

题解

STL search函数的使用,复杂度O(n^2)

PS:过气算法了,详情见KMP

代码

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 using namespace std;
 5 
 6 void Check(vector<int> vec1,vector<int> vec2){
 7     vector<int>::iterator iter1;
 8     iter1=search(vec1.begin(),vec1.end(),vec2.begin(),vec2.end());
 9     if(iter1!=vec1.end())
10         cout<<iter1-vec1.begin()+1<<" "<<iter1-vec1.begin()+vec2.size()<<endl;
11     else
12         cout<<"None"<<endl;
13 }
A

B.程序自动分析回到顶部

题意

n([1,10^5])个约束,i,j([1,10^9]),e=1代表xi=xj,e=0代表xi!=xj,问是否存在n个约束的满足的情况

题解

由于没有先后关系,所以把1全部拿出来,显然一定满足,我们用并查集把i,j都连起来

最后判断所有的0是否都满足

由于i,j范围很大,并查集内存不够

所以需要离散化,类似于哈希,复杂度O(nlogn)

PS:原题没给数据范围,感人连WAn次

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=1e5+5;
 5 struct node{
 6     int a,b,c;
 7     bool operator<(const node &d)const{
 8         return c>d.c;
 9     }
10 }a[N];
11 int d[N*2],f[N*2];
12 int find(int x){
13     return f[x]==x?x:f[x]=find(f[x]);
14 }
15 int main(){
16     int t;
17     scanf("%d",&t);
18     while(t--){
19         int n,tot=0;
20         scanf("%d",&n);
21         for(int i=1;i<=n;i++){
22             scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c);
23             d[++tot]=a[i].a;
24             d[++tot]=a[i].b;
25         }
26         sort(d+1,d+1+tot);
27         int sz=unique(d+1,d+1+tot)-d-1;
28         for(int i=1;i<=n;i++){
29             a[i].a=lower_bound(d+1,d+1+sz,a[i].a)-d;
30             a[i].b=lower_bound(d+1,d+1+sz,a[i].b)-d;
31         }
32         for(int i=1;i<=sz;i++)f[i]=i;
33         int flag=1;
34         sort(a+1,a+1+n);
35         for(int i=1;i<=n;i++){
36             int fa=find(a[i].a);
37             int fb=find(a[i].b);
38             if(a[i].c){
39                 f[fa]=fb;
40             }else if(fa==fb){
41                 flag=0;break;
42             }
43         }
44         printf("%s
",flag?"YES":"NO");
45     }
46     return 0;
47 }
B

C.Highway回到顶部

题意

高速公路(0,0)->(0,L),n个村庄(x,y),要求造最少的高速出口使得每个村庄距离最近的出口距离<=D,保证有解

题解

保证有解,那么以n个村庄为圆心,和y=0相交于xl和xr,我们令xl<0时xl=0,xr>L时xr=L,不影响解

那么问题就变成区间选点问题

按右端点从小到大排序,再按左端点从大到小排序

维护一个右端点r,如果r<a[i].l那么r=a[i].r,个数+1,复杂度O(nlogn)

PS:题目也太难读了

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=1e5+5;
 5 struct node{
 6     double l,r;
 7     bool operator<(const node &d)const{
 8         return r<d.r||(r==d.r&&l>d.l);
 9     }
10 }a[N];
11 int main(){
12     int l,d;
13     while(cin>>l>>d){
14         int n;
15         cin>>n;
16         for(int i=0;i<n;i++){
17             double x,y;
18             cin>>x>>y;
19             a[i].l=x-sqrt(d*d-y*y);
20             a[i].r=x+sqrt(d*d-y*y);
21             if(a[i].l<0)a[i].l=0;
22             if(a[i].r>l)a[i].r=l;
23         }
24         sort(a,a+n);
25         double val=a[0].r;
26         int ans=1;
27         for(int i=1;i<n;i++){
28             if(val<a[i].l){
29                 ans++;
30                 val=a[i].r;
31             }
32         }
33         cout<<ans<<endl;
34     }
35     return 0;
36 }
C

D.FQ 的气球回到顶部

题意

n([1,10^12])个气球排成一排,有m([1,10^5])种颜色,要求相邻两个颜色不同,并且k([1,2000])个气球颜色相同

题解

首先把k个气球按小到大排序,下标1开始

那么a[1]前和a[k]后的情况比较好考虑

m*(m-1)^(a[1]-1+n-a[k]),表示a[1]和a[k]有m种选择,其余点(m-1)种选择

然后就是考虑相邻的a[i]和a[i-1]的个数

由于a[i]和a[i-1]的颜色必须相同,所以把两个点看成一个点,然后就变成了一个环

设Fn表示放n个珠子的方案数,那么可以分成两种情况

1.考虑在n-1个珠子里插入一个珠子,方案数是(m-2)*Fn-1

2.考虑把n-2个珠子其中一个珠子分成两份并且在中间插入一个珠子,方案数是(m-1)*Fn-2

综合考虑为Fn=(m-1)*Fn-2+(m-2)*Fn-1,由于n很大,用矩阵快速幂求

F1=m,F2=m*(m-1),F3=需要特殊考虑,情况2不合法,所以(m-2)*F2

优化常数:由于Fn=(m-1)*Fn-2+(m-2)*Fn-1是一个二阶常数递推式,可以解得通项公式Fn=(m-1)^n+(-1)^n*(m-1)

最后,由于我们把每个相邻的个数求出来,最后乘起来,还需要除m^(k-1)把固定相同的排除掉

细节:当k=0时,m*(m-1)^(n-1)种方案

复杂度O(k2^3logn),优化常数做法变成O(klogn)

PS:暴躁詹老哥

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define LL long long
 5 
 6 const int P=1e9+7;
 7 int k;
 8 LL n,m,a[2005],f[4];
 9 struct mat{
10     LL a[2][2];
11     mat(){
12         memset(a,0,sizeof a);
13     }
14     mat operator*(const mat &b)const{
15         mat c;
16         for(int i=0;i<2;i++)
17             for(int j=0;j<2;j++)
18                 for(int k=0;k<2;k++)
19                     c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j]%P)%P;
20         return c;
21     }
22 };
23 mat quick_mat(mat a,LL b){
24     mat ans;
25     for(int i=0;i<2;i++)ans.a[i][i]=1;
26     while(b){
27         if(b&1)ans=ans*a;
28         a=a*a;
29         b>>=1;
30     }
31     return ans;
32 }
33 LL quick_LL(LL a,LL b){
34     LL ans=1;
35     while(b){
36         if(b&1)ans=ans*a%P;
37         a=a*a%P;
38         b>>=1;
39     }
40     return ans;
41 }
42 LL solve_mat(LL len){
43     if(len<=3)return f[len];
44     mat ans;
45     ans.a[0][0]=m-2;
46     ans.a[1][0]=m-1;
47     ans.a[0][1]=1;
48     ans=quick_mat(ans,len-3);
49     //for(int i=0;i<2;i++,printf("
"))
50     //    for(int j=0;j<2;j++)
51     //        printf("%lld ",ans.a[i][j]);
52     //puts("");
53     return (f[3]*ans.a[0][0]%P+f[2]*ans.a[1][0]%P)%P;
54 }
55 LL solve(){
56     //1 1 0
57     if(n==1)return m;
58     if(m==1)return 0;
59     if(k==0)return m*quick_LL(m-1,n-1)%P;
60     for(int i=2;i<=k;i++)if(a[i]-a[i-1]==1)return 0;
61     //两端
62     LL ans=m*quick_LL(m-1,a[1]-1+n-a[k])%P;
63     for(int i=2;i<=k;i++){
64         LL val=solve_mat(a[i]-a[i-1]);
65         //printf("i=%d %lld
",i,val);
66         ans=ans*val%P;
67     }
68     //把固定相同的排除掉
69     ans=ans*quick_LL(quick_LL(m,k-1),P-2)%P;
70     return ans;
71 }
72 int main(){
73     int t;
74     scanf("%d",&t);
75     while(t--){
76         scanf("%lld%lld%d",&n,&m,&k);
77         for(int i=1;i<=k;i++)scanf("%lld",&a[i]);
78         sort(a+1,a+1+k);
79         f[1]=m,f[2]=m*(m-1)%P,f[3]=(m-2)*f[2]%P;
80         printf("%lld
",solve());
81     }
82     return 0;
83 }
D
 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int N=2005;
 5 const int MD=1e9+7;
 6 ll b[N],n;
 7 int m,k;
 8 int quick_pow(int x,ll y) {
 9     int ans=1;
10     while(y) {
11         if(y&1) ans=1LL*ans*x%MD;
12         y>>=1;
13         x=1LL*x*x%MD;
14     }
15     return ans;
16 }
17 int gao(ll x) {
18     return (quick_pow(m-1,x)+(x&1?-m+1:m-1)+MD)%MD;
19 }
20 int cal() {
21     if(n==1) return m;
22     if(m==1) return 0;
23     if(k==0) return 1LL*m*quick_pow(m-1,n-1)%MD;
24     for(int i=1;i<k;i++) {
25         if(b[i]-b[i-1]==1) return 0;
26     }
27     int ans=1LL*m*quick_pow(m-1,b[0]-1+n-b[k-1])%MD;
28     for(int i=1;i<k;i++) {
29         ans=1LL*ans*gao(b[i]-b[i-1])%MD;
30     }
31     return 1LL*ans*quick_pow(quick_pow(m,k-1),MD-2)%MD;
32 }
33 int main() {
34     //freopen("in.txt","r",stdin);
35     int T;
36     scanf("%d",&T);
37     while(T--) {
38         scanf("%lld%d%d",&n,&m,&k);
39         for(int i=0;i<k;i++) {
40             scanf("%lld",&b[i]);
41         }
42         sort(b,b+k);
43         printf("%d
",cal());
44     }
45     return 0;
46 }
D公式优化

E.U的爱慕者回到顶部

题意

小明的悄悄话长度为N(5<=N<=100)必须按顺序输出,先从上到下n1个字符,再从左到右n2个字符,再从下到上n3个字符

必须保证n1=n3=max{ k | k <= n2 && 3 <= n2 <= N },n1 + n2 + n3 - 2 = N

题解

式子看不懂?没关系

直接枚举k,找一个最大的满足的就行

求出n1,n2,n3

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main(){
 5     string s;
 6     cin>>s;
 7     int sz=s.size();
 8     int n1=0,n2=0;
 9     for(int kn1=1;kn1<=sz;kn1++){
10         int kn2=sz+2-kn1-kn1;
11         if(kn1<=kn2){
12             n1=kn1;n2=kn2;
13         }
14     }
15     // printf("n1=%d n2=%d n3=%d
",n1,n2,n1);
16     int pl=0,pr=sz-1;
17     for(int i=0;i<n1;i++){
18         printf("%c",s[pl++]);
19         if(i<n1-1)for(int j=0;j<n2-2;j++)printf(" ");
20         else{
21             for(int j=pl;j<pr;j++)printf("%c",s[j]);
22         }
23         printf("%c",s[pr--]);
24         puts("");
25     }
26     return 0;
27 }
E

F.求绝对值回到顶部

题意

求实数的绝对值

题解

fabs(x),复杂度O(1)

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main(){
 5     double c;
 6     while(scanf("%lf",&c)!=EOF){
 7         printf("%.2f
",fabs(c));
 8     }
 9     return 0;
10 }
F

G.The Longest Sequence回到顶部

题意

Mirko必须找到最长的不同区间序列,以使序列中的每个区间都在集合中,并且每个区间都包含序列中的后续区间。

编写一个找到最长序列的程序

N([1,100000]),间隔A,B([1,1000000])

题解

区间按左端点从小到大,再按右端点从大到小

相当于左端点不用考虑,只考虑右端点,倒过来做一个最长上升子序列

然后发现如果只记录值,会导致左端点乱掉,WA掉

复杂度O(nlogn)

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=1e5+5;
 5 struct node{
 6     int l,r;
 7     bool operator<(const node &d)const{
 8         return l<d.l||(l==d.l&&r>d.r);
 9     }
10 }a[N];
11 int d[N],did[N],tot,pre[N];
12 int main(){
13     int n;
14     scanf("%d",&n);
15     for(int i=0;i<n;i++){
16         scanf("%d%d",&a[i].l,&a[i].r);
17     }
18     sort(a,a+n);
19     //for(int i=0;i<n;i++)
20         //printf("%d %d
",a[i].l,a[i].r);
21     for(int i=n-1;i>=0;i--){
22         if(tot==0||a[i].r>=d[tot-1]){
23             pre[i]=(tot==0?-1:did[tot-1]);did[tot]=i;d[tot++]=a[i].r;
24         }else{
25             int pos=upper_bound(d,d+tot,a[i].r)-d;
26             //printf("pos=%d
",pos);
27             d[pos]=a[i].r;did[pos]=i;pre[i]=(pos==0?-1:did[pos-1]);
28         }
29         //printf("i=%d put=%d {%d,%d} %d tot=%d
",i,pre[i],a[i].l,a[i].r,pre[i],tot);
30         //puts("");
31     }
32     printf("%d
",tot);
33     for(int i=did[tot-1];i>-1;i=pre[i]){
34         printf("%d %d
",a[i].l,a[i].r);
35     }
36     return 0;
37 }
38 /*
39 10
40 1 8
41 1 9
42 2 8
43 3 9
44 1 50
45 1 8
46 5 9
47 2 10
48 2 100
49 2 5
50 */
G

H.等边字符三角形回到顶部

题意

N*N([1,256])的图,求等边三角形个数

题解

维护一个前缀和表示i,j前有几个连续的'#'

枚举每个'#'按照前缀和求出所有个数

PS:感谢学弟指出

假算法:看似复杂度O(n^4)不行

仔细算一下,有很多优化的小地方,详情见代码

当256*256个'#'时达到最坏复杂度,经打表得到O(134209536≈1.3e8)爬过

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int pre[260][260];
 5 char G[260][260];
 6 int main(){
 7     int n;
 8     while(scanf("%d",&n)!=EOF){
 9         for(int i=1;i<=n;i++)scanf("%s",G[i]+1);
10         // for(int i=1;i<=n;i++)
11         //     for(int j=1;j<=n;j++)
12         //         G[i][j]='#';
13         for(int i=1;i<=n;i++)
14             for(int j=1;j<=n;j++){
15                 if(G[i][j]=='.')pre[i][j]=0;
16                 else pre[i][j]=pre[i][j-1]+1;
17             }
18         int ans=0;
19         for(int i=1;i<=n;i++)
20             for(int j=1;j<=n;j++){
21                 if(G[i][j]=='.')continue;
22                 for(int x=0;i+x<=n&&j+x<=n&&2*x+1<=n&&x<=n-i;x++)
23                     if(pre[i+x][j+x]>=2*x+1)
24                         ans++;
25                     else break;
26             }
27         printf("%d
",ans);
28     }
29     return 0;
30 }
H

I.All Discs Considered回到顶部

题意

两张DVD,1张里有D1个软件,1张里有D2个软件,([1,50000]),D个约束([1,100000]),表示a软件要在b软件前安装,CD驱动器一次只能由1张DVD,问至少需要替换几次,一开始放进去和最后拿出来都算一次

题解

如果我们知道第一次放进去的是哪张DVD

按照拓扑排序,把改DVD所有软件度数为的0的拿出来,换DVD这样操作,复杂度O(n)

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=1e5+5;
 5 vector<int>G[N];
 6 stack<int>st[2];
 7 int d[2][N];
 8 int main(){
 9     int n1,n2,D,x,y;
10     while(scanf("%d%d%d",&n1,&n2,&D),n1||n2||D){
11         int n=n1+n2;
12         for(int i=1;i<=n;i++)G[i].clear(),d[0][i]=d[1][i]=0;
13         for(int i=1;i<=D;i++){
14             scanf("%d%d",&x,&y);
15             if(x<=n1&&y<=n1);
16             else if(x>n1&&y>n1);
17             else{
18                 //printf("%d->%d
",x,y);
19                 G[x].push_back(y);
20                 d[0][y]++,d[1][y]++;
21             }
22         }
23         int ans=1,minn=1e9;
24         //DVD1
25         int als=0;
26         int p=0;
27         for(int i=1;i<=n;i++)
28             if(d[0][i]==0)
29                 st[i<=n1?0:1].push(i);
30         while(1){
31             while(!st[p].empty()){
32                 als++;
33                 int u=st[p].top();st[p].pop();
34                 for(int i=0;i<G[u].size();i++){
35                     int v=G[u][i];
36                     if(--d[0][v]==0)
37                         st[v<=n1?0:1].push(v);
38                 }
39             }
40             if(als==n)break;
41             ans++;
42             p=1-p;
43         }
44         //printf("1 = %d
",ans+1);
45         minn=min(ans+1,minn);
46         while(!st[0].empty())st[0].pop();
47         while(!st[1].empty())st[1].pop();
48         p=1;
49         ans=1;als=0;
50         for(int i=1;i<=n;i++)
51             if(d[1][i]==0)
52                 st[i<=n1?0:1].push(i);
53         while(1){
54             while(!st[p].empty()){
55                 als++;
56                 int u=st[p].top();st[p].pop();
57                 for(int i=0;i<G[u].size();i++){
58                     int v=G[u][i];
59                     if(--d[1][v]==0)
60                         st[v<=n1?0:1].push(v);
61                 }
62             }
63             if(als==n)break;
64             ans++;
65             p=1-p;
66         }
67         while(!st[0].empty())st[0].pop();
68         while(!st[1].empty())st[1].pop();
69         //printf("2 = %d
",ans+1);
70         minn=min(ans+1,minn);
71         printf("%d
",minn);
72     }
73     return 0;
74 }
I
原文地址:https://www.cnblogs.com/taozi1115402474/p/12384891.html