• 1109-1110膜你赛


    1109-1110两天时间两场模拟赛,总结一下;

    1.prime

      质数也叫素数,指除了1和它本身没有其他因子的整数。

       质数是数论中很特殊的数,作用也很大,小x也在研究。

       小x对小y说,你给我一个数字,我可以告诉你这个数字是不是质数。读题的你肯定很不屑小x的自大,这个还用说,只要学习OI的都会。

       那么小x的问题就改为:给你一个区间[X,Y],问从X到Y有多少个质数。

     

    题意:给出一个区间,问在这个区间有多少素数?区间大小10^6,区间范围int;

    题解:这种题很容易想到筛法,int的数据范围,质因数不超过50000,枚举1-50000内所有质数,然后区间跳格子一样的一个个标记上,最后统计有多少个没被标记即可;

    复杂度:nlogn (自然对数)

     1 /*chad*/
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<cstdlib>
     6 #include<cstring>
     7 #include<algorithm>
     8 using namespace std;
     9 const int maxn(1000005),inf(1000000);
    10 #define FILE "prime"
    11 #define LL long long
    12 #define up(i,j,n) for(LL i=(j);(i)<=(n);(i)++)
    13 namespace IO{
    14     char buf[1<<15],*fs,*ft;
    15     LL gc(){return (fs==ft&&((ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft))?-1:*fs++;}
    16     LL read(){
    17         LL x=0,ch=gc(),f=0;
    18         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    19         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    20         return f?-x:x;
    21     }
    22 }using namespace IO;
    23 LL x,y;
    24 LL prime[maxn],b[maxn],tail=0;
    25 void getprime(){
    26     for(LL i=2;i<=inf;i++){
    27         if(!b[i])prime[++tail]=i;
    28         for(LL j=1;prime[j]*i<=inf&&j<=tail;j++){
    29             b[prime[j]*i]=1;
    30             if(i%prime[j]==0)break;
    31         }
    32     }
    33 }
    34 LL f[maxn];
    35 int main(){
    36     freopen(FILE".in","r",stdin);
    37     freopen(FILE".out","w",stdout);
    38     cin>>x>>y;
    39     getprime();
    40     LL ans=0,s;
    41     for(LL i=1;i<=tail&&prime[i]<=y;i++){
    42         s=x+(prime[i]-x%prime[i])%prime[i];
    43         for(LL j=s;j<=y;j+=prime[i]){
    44             f[j-x]=1;
    45         }
    46         if(prime[i]>=x&&prime[i]<=y)f[prime[i]-x]=0;
    47     }
    48     for(LL i=0;i<=y-x;i++)if(!f[i])ans++;
    49     if(x==1)ans--;
    50     cout<<ans<<endl;
    51     return 0;
    52 }
    View Code

    2. 飞天

        小x和他的小伙伴们创作了一个舞蹈——飞天。

        这个舞蹈由N个小朋友一起来完成,编号分别为[1..N]。每位小朋友都被威亚吊着飞在天空中,每个人的高度为H[i],做着各种高难度动作。

        小x作为导演,又有了新的想法,他把舞蹈分为M大部分。每部分只挑选编号连续的某些小朋友,升到相同的高度,做相应的表演。等本部分表演结束,小朋友的高度会自动恢复到原来的高度。

        但是,现在每次调整高度难坏了小x,并且每位选手调整的高度增加或减少1,小x就要花费单位为1的能量,小x就想知道,怎么安排调整高度,能让自己消耗的能量最少。

    【数据范围】

    对于50%的数据 n≤500,m≤1000;

    对于80%的数据 n≤1000,m≤100000;

    对于100%的数据n≤1000,m≤200000;

    答案小于2^64。

     

     

    题意:给定m个区间,求出每个区间所有数与中位数的绝对值之和;

    题解:m特别大,肯定不能直接求,由于n只有1000,考虑做一个预处理;

    设f[i][j]表示i到j的所求答案,n^2的枚举,怎么在加入一个新数后维护答案?

    用两个堆(priority_queue)可以做到log级别的转移,O(n^2logn)的预处理,代码简单,速度不错;

    我使用的是treap找第k大的方法找中位数,顺便维护比中位数小的数的和,尽管很直观,但我考试时就感觉不对,我只需要维护一个中位数和比中位数小的数的和,就用上了平衡树,太浪费了(我的预感也确实是对的了,标解是堆);

    chty用的是莫队,使用平衡树(log)转移,复杂度O(n1/2mlog);

    学长使用线段树维护一个区间内的所有的数值,这种方法在考试时考虑过,但hi无数据范围,我不太敢用,放弃了,使用了平衡树(平衡树调得我欲仙欲死,还需要提升代码能力);

     1 /*chad*/
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<cstdlib>
     6 #include<cstring>
     7 #include<algorithm>
     8 #include<ctime>
     9 #include<string>
    10 using namespace std;
    11 const int maxn(1005),inf(1000000);
    12 #define FILE "sky"
    13 #define LL long long
    14 #define up(i,j,n) for(LL i=(j);(i)<=(n);(i)++)
    15 namespace IO{
    16     char buf[1<<15],*fs,*ft;
    17     LL gc(){return (fs==ft&&((ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft))?-1:*fs++;}
    18     LL read(){
    19         LL x=0,ch=gc(),f=0;
    20         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    21         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    22         return f?-x:x;
    23     }
    24 }using namespace IO;
    25 LL a[maxn];
    26 int n,m;
    27 struct node{
    28     LL ch[2];
    29     LL r,v,siz,cnt,sum;
    30     LL cmp(LL x){return x>v;}
    31 }e[maxn];
    32 LL len=0,root=0;
    33 void updata(LL o){e[o].siz=e[e[o].ch[0]].siz+e[e[o].ch[1]].siz+e[o].cnt;e[o].sum=e[e[o].ch[0]].sum+e[e[o].ch[1]].sum+e[o].v*e[o].cnt;}
    34 void rotate(LL &o,LL d){
    35     LL k=e[o].ch[d];
    36     e[o].ch[d]=e[k].ch[d^1];
    37     e[k].ch[d^1]=o;
    38     updata(o);updata(k);
    39     o=k;
    40 }
    41 void insert(LL &o,LL x){
    42     if(o==0){o=++len;e[o].v=x;e[o].r=rand();e[o].cnt=1;e[o].siz=1;e[o].ch[0]=e[o].ch[1]=0;e[o].sum=x;return;}
    43     if(x==e[o].v){e[o].cnt++;updata(o);return;}
    44     LL d=e[o].cmp(x);
    45     insert(e[o].ch[d],x);
    46     updata(o);
    47     if(e[e[o].ch[d]].r>e[o].r)rotate(o,d);
    48 }
    49 pair<LL,LL> getK(LL k){
    50     LL o=root;
    51     LL left=0;
    52     while(o){
    53         if(k>e[e[o].ch[0]].siz&&k<=e[e[o].ch[0]].siz+e[o].cnt)return make_pair(o,left+e[e[o].ch[0]].sum+e[o].v*e[o].cnt-e[o].v*(e[e[o].ch[0]].siz+e[o].cnt-k+1));
    54         if(k>e[e[o].ch[0]].siz+e[o].cnt)k=k-e[e[o].ch[0]].siz-e[o].cnt,left+=e[e[o].ch[0]].sum+e[o].cnt*e[o].v,o=e[o].ch[1];
    55         else o=e[o].ch[0];
    56     }
    57     return make_pair(o,left);
    58 }
    59 LL f[maxn][maxn];
    60 int main(){
    61     freopen(FILE".in","r",stdin);
    62     freopen(FILE".out","w",stdout);
    63     n=read(),m=read();
    64     up(i,1,n)a[i]=read();
    65     LL sum=0,o,mid;
    66     srand(time(0));
    67     for(LL i=1;i<=n;i++){
    68         len=0;root=0;sum=0;
    69         for(LL j=i;j<=n;j++){
    70             insert(root,a[j]);
    71             sum+=a[j];
    72             pair<LL,LL> p=getK((j-i+1)/2+1);
    73             o=p.first;
    74             mid=e[o].v;
    75             f[i][j]+=(j-i+1)/2*mid-p.second;
    76             f[i][j]+=sum-p.second-mid-mid*(j-i+1-((j-i+1)/2+1));
    77         }
    78     }
    79     int x,y;
    80     LL ans=0;
    81     while(m--){
    82         x=read(),y=read();
    83         ans+=f[x][y];
    84     }
    85     cout<<ans<<endl;
    86     return 0;
    87 }
    View Code

    3.树

     Fanvree很聪明,解决难题时他总会把问题简单化。

    例如,他就整天喜欢把图转化为树。但是他不会缩环,那他怎么转化呢?

    这是一个有n个点m条双向边的图,Fanvree会选定一个节点,然后删掉这个节点和这个点连出去的边,如果变成了一棵树,那么这个节点便是可行的,什么是树呢?树也即无简单环的无向连通图。

    现在你需要告诉Fanvree可能的节点是什么。

     

     

    题意:让你找到图上的所有节点,使删掉它后图成为一棵树;

    题解:

    要找到一个节点使删掉它之后图变成一颗树,本身就有着极苛刻的条件,只要这个点的度数符合要求就可以;

    扫一遍度数,再用tarjan判断一下这个点是不是割点,符合条件输出; 

     1 /*chad*/
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<cstdlib>
     6 #include<cstring>
     7 #include<algorithm>
     8 #include<ctime>
     9 #include<string>
    10 using namespace std;
    11 const int maxn(200005),inf(1000000000);
    12 #define FILE "tree"
    13 #define LL long long
    14 #define up(i,j,n) for(LL i=(j);(i)<=(n);(i)++)
    15 namespace IO{
    16     char buf[1<<15],*fs,*ft;
    17     LL gc(){return (fs==ft&&((ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft))?-1:*fs++;}
    18     LL read(){
    19         LL x=0,ch=gc(),f=0;
    20         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    21         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    22         return f?-x:x;
    23     }
    24 }using namespace IO;
    25 int n,m;
    26 struct node{
    27     int y,next;
    28 }e[maxn<<1];
    29 int linkk[maxn],len=0,ru[maxn];
    30 void insert(int x,int y){
    31     e[++len].y=y;
    32     e[len].next=linkk[x];
    33     linkk[x]=len;
    34 }
    35 int pre[maxn],low[maxn],dfs_clock=0,child[maxn],vis[maxn];
    36 void dfs(int x,int fa){
    37     pre[x]=low[x]=++dfs_clock;
    38     for(int i=linkk[x];i;i=e[i].next){
    39         if(e[i].y==fa)continue;
    40         if(!pre[e[i].y]){
    41             child[x]++;
    42             dfs(e[i].y,x);
    43             if(low[e[i].y]>=pre[x])vis[x]=1;
    44             low[x]=min(low[x],low[e[i].y]);
    45         }
    46         else low[x]=min(low[x],pre[e[i].y]);
    47     }
    48     if(x==1&&child[x]==1)vis[x]=0;
    49 }
    50 int q[maxn],tail=0;
    51 int main(){
    52     n=read(),m=read();
    53     int x,y;
    54     up(i,1,m){
    55         x=read(),y=read();
    56         insert(x,y);insert(y,x);
    57         ru[x]++,ru[y]++;
    58     }
    59     dfs(1,0);
    60     for(int i=1;i<=n;i++)if(ru[i]==m-n+2&&!vis[i])q[++tail]=i;
    61     printf("%d
    ",tail);
    62     for(int i=1;i<=tail;i++)printf("%d ",q[i]);
    63     return 0;
    64 }
    View Code

    1.一道usaco的改编题

    现在给定一个特殊的计数方式,混合进制数。也就是给定一个多位数,每位数上的进制都是不一样的。

    比如给定一个三位数:这三位数的进制分别是2 3 2.也就是最小的位数逢2进1,次小位数逢3进制,最高位逢2进1.

    那么,这个混合进制数最小数是0,最大数是121。一共有2*3*2=12个数。

    分别是:000,001,010,011,020,021,100,101,110,111,120,121。

    如果我想知道第7大的数,就是100.

    现在的问题就是,给你每个位数上的进制,你找出从0开始,第k个数是多少?

     1 /*chad*/
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<cstdlib>
     6 #include<cstring>
     7 #include<algorithm>
     8 #include<ctime>
     9 #include<string>
    10 using namespace std;
    11 const int maxn(50),inf(1000000000);
    12 #define FILE "spehex"
    13 #define LL long long
    14 #define up(i,j,n) for(int i=(j);(i)<=(n);(i)++)
    15 namespace IO{
    16     char buf[1<<15],*fs,*ft;
    17     int gc(){return (fs==ft&&((ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft))?-1:*fs++;}
    18     LL read(){
    19         LL x=0,ch=gc(),f=0;
    20         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    21         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    22         return f?-x:x;
    23     }
    24 }using namespace IO;
    25 int n,a[maxn],k,m;
    26 char s[maxn];
    27 int main(){
    28     freopen(FILE".in","r",stdin);
    29     freopen(FILE".out","w",stdout);
    30     n=read();
    31     for(int i=1;i<=n;i++)a[i]=read();
    32     m=read();
    33     while(m--){
    34         k=read();k--;
    35         if(k<0){
    36             printf("0
    ");
    37             continue;
    38         }
    39         for(int i=n;i>=1;i--){
    40             s[i]=k%a[i]+'0';
    41             k/=a[i];
    42             if(!k){
    43                 printf("%s
    ",s+i);
    44                 break;
    45             }
    46         }
    47         if(k)printf("-1
    ");
    48     }
    49     return 0;
    50 }
    View Code

    题解:模拟

    2.旅行

        小x要去旅游了。他决定开一辆耗油量很高的巨大的拉风的tank去旅游了。

        这辆tank有一个巨大的油箱,可以装满G升燃油。tank是很费油的,每升燃油只够tank跑一公里,而小x的旅程要有D公里要跑。

        虽然油箱很大,但是,显然旅途中是需要加油的。

        小x得到了旅途中加油站的信息,一共有N个加油站,第i个加油站距离起点的距离为X_i(0 <= X_i <= D),每公升燃油价格为Y_i元(1 <= Y_i <= 1,000,000)。

        现在小x想知道,如果出发时,tank里已经有B公升燃油(0 <= B <= D),那么,他最少花费多少钱,可以完成整个旅途。

        如果中间因为燃油不够而无法完成旅程,那么你需要输出-1.  

    30%  数据保证  N<=100   G<=1000  D<=10000  

    60%  数据保证  N<=5000  G<=1000  D<=10000000 

    100% 数据 1 <= G <= 1,000,000  1 <= D <= 1,000,000,000  1 <= N <= 50,000

     1 /*chad*/
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<cstdlib>
     6 #include<cstring>
     7 #include<algorithm>
     8 #include<ctime>
     9 #include<string>
    10 #include<map>
    11 #include<set>
    12 using namespace std;
    13 const int maxn(50100),inf(1000000000);
    14 #define FILE "fule"
    15 #define LL long long
    16 #define up(i,j,n) for(LL i=(j);(i)<=(n);(i)++)
    17 namespace IO{
    18     char buf[1<<15],*fs,*ft;
    19     LL gc(){return (fs==ft&&((ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft))?-1:*fs++;}
    20     LL read(){
    21         LL x=0,ch=gc(),f=0;
    22         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    23         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    24         return f?-x:x;
    25     }
    26 }using namespace IO;
    27 LL n,g,b,d;
    28 struct node{
    29     LL d,y;
    30     bool operator<(const node& b)const{return d<b.d;}
    31 }e[maxn];
    32 LL q[maxn],r[maxn],v[maxn],head=1,tail=0,sum=0;
    33 LL ans=0;
    34 void print(LL x){printf("%d
    ",x);exit(0);}
    35 int main(){
    36     freopen(FILE".in","r",stdin);
    37     freopen(FILE".out","w",stdout);
    38     n=read(),g=read(),sum=b=read(),d=read();
    39     up(i,1,n)e[i].d=read(),e[i].y=read();
    40     n++;e[n].d=d;e[n].y=0;
    41     sort(e+1,e+n+1);
    42     up(i,1,n)r[i]=e[i].d-e[i-1].d;
    43     q[++tail]=b;v[tail]=0;
    44     for(LL i=1;i<=n;i++){
    45         if(sum-r[i]<0)print(-1);
    46         while(r[i]){
    47             if(r[i]>=q[head])r[i]-=q[head],sum-=q[head],head++;
    48             else q[head]-=r[i],sum-=r[i],r[i]=0;
    49         }
    50         while(v[tail]>e[i].y&&head<=tail)sum-=q[tail],ans-=q[tail]*v[tail],tail--;
    51         q[++tail]=g-sum;v[tail]=e[i].y;ans+=e[i].y*(g-sum);sum=g;
    52     }
    53     cout<<ans<<endl;
    54     return 0;
    55 }
    View Code

    题解:

    是道好题,值得一做;

    最初想到设f[i][j],设状态转移方程写,复杂度O(n^3),很暴力;

    考虑一下用单调队列;

    我们可以想象,我们车子的油是可以退回的,也就是只有燃烧的油才会真正花钱,那么我们每次进站之后,都先将油加满,等到到了下一个加油站发现了更便宜的油,我们把贵的油都退了,再把便宜的油加满油箱,这样就可以用单调队列实现这道题;

    复杂度:O(n);

    3.journey

    给出一个长度为 N 的由小写字母’a’~’z’和’*’组成的字符串 A,一个长度为 M 的仅由小

    写字母’a’~’z’组成的字符串 B。一个’*’可以匹配任意多个字符(包括 0 个)。求在 B 的所有 循环同构串中,有多少个能够与 A 匹配。

    循环同构串:就是把 B 的前 k 个字母(0<=k<M)移到结尾所得到的字符串。例如 abc 的 循环同构串有 abc、bca 和 cab。

    A 与 B 匹配:若除了 A 中的’*’号可以匹配 B 中的任意多个字符外,其余字符一一对应, 则称 A 与 B 匹配。例如 a*b*c 与 aadbc 是匹配的,其中第一个*对应 ad,第二个*对应空串。

     

    对于 30% 的测试点,M≤20。

    对于 80% 的测试点,M≤200。

    对于 100% 的测试点,1<=N<=100,1≤M≤100000。

     

     1 /*chad*/
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<cstdlib>
     6 #include<cstring>
     7 #include<algorithm>
     8 #include<ctime>
     9 #include<string>
    10 using namespace std;
    11 const int maxn(110000),inf(1000000);
    12 #define FILE "journey"
    13 #define LL long long
    14 #define up(i,j,n) for(int i=(j);(i)<=(n);(i)++)
    15 namespace IO{
    16     char buf[1<<15],*fs,*ft;
    17     int gc(){return (fs==ft&&((ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft))?-1:*fs++;}
    18     LL read(){
    19         LL x=0,ch=gc(),f=0;
    20         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    21         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    22         return f?-x:x;
    23     }
    24 }using namespace IO;
    25 char ch[maxn],s[maxn<<1];
    26 int n,m;
    27 char t[110][110];
    28 int top=0,cnt[110];
    29 int next[110][110];
    30 bool vis[maxn<<1][110];
    31 int f[maxn<<1][110];
    32 int main(){
    33     freopen(FILE".in","r",stdin);
    34     freopen(FILE".out","w",stdout);
    35     scanf("%s",ch);scanf("%s",s);
    36     n=strlen(ch);m=strlen(s);
    37     for(int i=0;i<m;i++)s[i+m]=s[i];
    38     m=strlen(s);
    39     for(int i=0;i<n;i++){
    40         if(ch[i]!='*'){
    41             top++;
    42             for(;i<n&&ch[i]!='*';i++){
    43                 t[top][cnt[top]++]=ch[i];
    44             }
    45         }
    46     }
    47     for(int k=1;k<=top;k++){
    48         int j=-1;next[k][0]=-1;
    49         for(int i=1;i<cnt[k];i++){
    50             while(j!=-1&&t[k][i]!=t[k][j+1])j=next[k][j];
    51             if(t[k][i]==t[k][j+1])j++;
    52             next[k][i]=j;
    53         }
    54     }
    55     for(int k=1;k<=top;k++){
    56         int j=-1;
    57         for(int i=0;i<m;i++){
    58             while(s[i]!=t[k][j+1]&&j!=-1)j=next[k][j];
    59             if(s[i]==t[k][j+1])j++;
    60             if(j==cnt[k]-1){
    61                 vis[i-cnt[k]+1][k]=1;
    62                 j=next[k][j];
    63             }
    64         }
    65     }
    66     memset(f,10,sizeof(f));
    67     for(int i=m-1;i>=0;i--){
    68         for(int j=1;j<=top;j++){
    69             if(vis[i][j])f[i][j]=i;
    70             else f[i][j]=f[i+1][j];
    71         }
    72     }
    73     int ans=0;
    74     for(int i=0;i<m/2;i++){
    75         if(ch[0]!='*'&&!vis[i][1])continue;
    76         if(ch[n-1]!='*'&&!vis[i-cnt[top]+m/2][top])continue;
    77         int now=i;
    78         for(int k=1;k<=top;k++){
    79             now=f[now][k]+cnt[k];
    80             if(now>inf)break;
    81         }
    82         if(now<=i+m/2)ans++;
    83     }
    84     cout<<ans<<endl;
    85     return 0;
    86 }
    View Code

    题解:

    (先吐个槽,80%的数据范围那么小,我们还有什么心思去优化,打暴力得了)

    80%,nm都是100左右,如果单个匹配,参照最长公共子序列n^2dp,题目强行加了一个循环,O(n^3)80分到手;

    100%,M上涨到了100000,先对M进行一下复制加长,然后处理每个A串片段在B串中出现的位置,最后枚举B串开头点,再判断一下在M的范围内是否可以找全所有片段;

    复杂度O(n*m);

     

  • 相关阅读:
    个人作业-数组3
    Java编程思想
    19年春第三周学习
    个人作业-数组2
    自我介绍
    个人作业-数组
    19春第二周学习心得
    fiddler--华为手机下载安装fiddler证书
    RF接口测试----post请求
    RF接口测试----get请求
  • 原文地址:https://www.cnblogs.com/chadinblog/p/6051209.html
Copyright © 2020-2023  润新知