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\n",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\n");
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\n",s+i);
44                 break;
45             }
46         }
47         if(k)printf("-1\n");
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\n",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);

 

posted @ 2016-11-10 15:43  CHADLZX  阅读(448)  评论(0编辑  收藏  举报