zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Codeforces Round #452 F. Letters Removing
    bzoj 1492: [NOI2007]货币兑换Cash
    bzoj 4016: [FJOI2014]最短路径树问题
    bzoj 2109: [Noi2010]Plane 航空管制
    bzoj 1058: [ZJOI2007]报表统计
    bzoj 1016: [JSOI2008]最小生成树计数
    bzoj 1013: [JSOI2008]球形空间产生器sphere
    bzoj 1758: [Wc2010]重建计划
    bzoj 2337: [HNOI2011]XOR和路径
    一本通1668取石子
  • 原文地址:https://www.cnblogs.com/taozi1115402474/p/12384891.html
Copyright © 2011-2022 走看看