Part1--模拟题
今天是最后一天有模拟题,然而不知道为什么,我们这个区好多人的程序没有收上去(包括我)。所以至今也不知道自己多少分。不过前两题都是打的暴力(觉得自己除了暴力真的是什么都不会。。)
还是看一下题吧
(第一题)
1.计数
(count.cpp/c/pas)
时间限制:1s
内存限制:256MB
【问题描述】
给出m个数a[1],a[2],…,a[m]
求1~n中有多少数不是a[1],a[2],…,a[m]的倍数。
【输入】
输入文件名为count.in。
第一行,包含两个整数:n,m
第二行,包含m个数,表示a[1],a[2],…,a[m]
【输出】
输出文件名为count.out。
输出一行,包含1个整数,表示答案
【输入输出样例】
count.in | count.out |
10 2 2 3 | 3 |
【数据说明】
对于60%的数据,1<=n<=106
对于另外20%的数据,m=2
对于100%的数据,1<=n<=109,0<=m<=20,1<=a[i]<=109
60分做法:纯枚举。
100分做法:容斥原理。
这个可以由‘另外20%的数据’来推出:如果m=2的话,如下图:
易得:ans=A+B-(A交B)
扩展一下,在m!=2的时候也是同理。
我的代码:
1 #include <iostream> 2 #include <cmath> 3 #include <cstring> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <algorithm> 7 using namespace std; 8 bool a[1010101]; 9 int read() 10 { 11 int t=0,f=1; 12 char ch=getchar(); 13 while(ch<'0' || ch>'9') 14 { 15 if(ch=='-') {f=-1;ch=getchar();} 16 } 17 while(ch>='0' && ch<='9') {t=t*10+ch-'0';ch=getchar();} 18 return t*f; 19 } 20 int main() 21 { 22 /*freopen("count.in","r",stdin); 23 freopen("count.out","w",stdout);*/ 24 int n,m; 25 n=read();m=read(); 26 int cnt=0; 27 for(int i=1;i<=m;i++) 28 { 29 int x; 30 x=read(); 31 for(int j=x;j<=n;j+=x) 32 { 33 if(!a[j]) {a[j]=1;cnt++;} 34 //cout<<"i="<<i<<" j="<<j<<" cnt="<<cnt<<endl; 35 } 36 } 37 printf("%d",n-cnt); 38 system("pause"); 39 return 0; 40 }
标程(有一半都是头文件和各种define):
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 using namespace std; 8 typedef long long ll; 9 typedef long double ld; 10 typedef pair<int,int> pr; 11 const double pi=acos(-1); 12 #define rep(i,a,n) for(int i=a;i<=n;i++) 13 #define per(i,n,a) for(int i=n;i>=a;i--) 14 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 15 #define clr(a) memset(a,0,sizeof a) 16 #define pb push_back 17 #define mp make_pair 18 #define putk() putchar(' ') 19 ld eps=1e-9; 20 ll pp=1000000007; 21 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 22 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 23 ll gcd(ll a,ll b){return (!b)?a:gcd(b,a%b);} 24 ll read(){ 25 ll ans=0; 26 char last=' ',ch=getchar(); 27 while(ch<'0' || ch>'9')last=ch,ch=getchar(); 28 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar(); 29 if(last=='-')ans=-ans; 30 return ans; 31 } 32 void put(ll a){ 33 if(a<0)putchar('-'),a=-a; 34 int top=0,q[20]; 35 while(a)q[++top]=a%10,a/=10; 36 top=max(top,1); 37 while(top--)putchar('0'+q[top+1]); 38 } 39 //head 40 ll ans=0; 41 int n,m,a[25]; 42 ll Gcd(ll a,ll b){ 43 if(!b)return a; 44 return gcd(b,a%b); 45 } 46 void dfs(int dep,ll t,int flag){ 47 if(t>n)return; 48 if(dep==m+1){ 49 ans+=n/t*flag; 50 return; 51 } 52 dfs(dep+1,t,flag); 53 dfs(dep+1,t/Gcd(t,a[dep])*a[dep],-flag); 54 } 55 int main(){ 56 n=read(); 57 m=read(); 58 rep(i,1,m)a[i]=read(); 59 dfs(1,1,1); 60 cout<<ans<<endl; 61 return 0; 62 }
(2)第二题
2.第k大区间
(kth.cpp/c/pas)
时间限制:1s
内存限制:256MB
【问题描述】
定义一个长度为奇数的区间的值为其所包含的的元素的中位数。
现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少。
【输入】
输入文件名为kth.in。
第一行两个数n和k
第二行,n个数。(0<=每个数<231)
【输出】
输出文件名为kth.out。
一个数表示答案。
【输入输出样例】
kth.in | kth.out |
4 3 3 1 2 4 | 2
|
【样例解释】
[l,r]表示区间l~r的值
[1,1]:3
[2,2]:1
[3,3]:2
[4,4]:4
[1,3]:2
[2,4]:2
【数据说明】
对于30%的数据,1<=n<=100;
对于60%的数据,1<=n<=300
对于80%的数据,1<=n<=1000
对于100%的数据,1<=n<=100000, k<=奇数区间的数
30%做法:枚举+排序 O(n^3logn)
60%做法:固定左端点,每次改变右端点只需加上1个点,如果新来的数比较小,就和之前的交换。 O(n^3)
*求最大值、最小值、第k大,有90%都是二分答案*
100%做法:二分答案--->转为逆序对问题(前缀和) O(nlognlogn)
我的代码(依然是暴力。。):
1 #include <iostream> 2 #include <cmath> 3 #include <cstring> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <algorithm> 7 using namespace std; 8 int a[101010],b[101010],c[101010]; 9 int read() 10 { 11 int t=0,f=1; 12 char ch=getchar(); 13 while(ch<'0' || ch>'9') 14 { 15 if(ch=='-') {f=-1;ch=getchar();} 16 } 17 while(ch>='0' && ch<='9') {t=t*10+ch-'0';ch=getchar();} 18 return t*f; 19 } 20 21 22 int main() 23 { 24 freopen("kth.in","r",stdin); 25 freopen("kth.out","w",stdout); 26 int n,k; 27 n=read();k=read(); 28 for(int i=1;i<=n;i++) a[i]=read(); 29 int cnt=0,cnt1=0; 30 for(int i=1;i<=n;i++) 31 { 32 cnt=0; 33 memset(b,0,sizeof(b)); 34 for(int j=i;j<=n;j+=2) 35 { 36 b[++cnt]=a[j]; 37 if(j-1>i) b[++cnt]=a[j-1]; 38 sort(b+1,b+cnt+1); 39 c[++cnt1]=b[(j-i+1)/2+1]; 40 //cout<<"i="<<i<<" j="<<j<<" c[cnt1]="<<c[cnt1]<<endl; 41 } 42 } 43 sort(c+1,c+cnt1+1); 44 printf("%d",c[n-k+1]); 45 //system("pause"); 46 return 0; 47 }
标程:
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 using namespace std; 8 typedef long long ll; 9 typedef long double ld; 10 typedef pair<int,int> pr; 11 const double pi=acos(-1); 12 #define rep(i,a,n) for(int i=a;i<=n;i++) 13 #define per(i,n,a) for(int i=n;i>=a;i--) 14 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 15 #define clr(a) memset(a,0,sizeof a) 16 #define pb push_back 17 #define mp make_pair 18 #define fi first 19 #define sc second 20 ld eps=1e-9; 21 ll pp=1000000007; 22 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 23 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 24 ll read(){ 25 ll ans=0; 26 char last=' ',ch=getchar(); 27 while(ch<'0' || ch>'9')last=ch,ch=getchar(); 28 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar(); 29 if(last=='-')ans=-ans; 30 return ans; 31 } 32 //head 33 #define N 110000 34 int a[N],b[N],c[N],d[N],e[N],n,m; 35 ll k; 36 int lowbit(int x){ 37 return x&(-x); 38 } 39 int bin(int k){ 40 int l=1,r=m; 41 while(l<r){ 42 int mid=(l+r)/2; 43 if(k<=d[mid])r=mid; 44 else l=mid+1; 45 } 46 return l; 47 } 48 void add(int x){ 49 for(;x<=m;x+=lowbit(x))e[x]++; 50 } 51 int find(int x){ 52 int ans=0; 53 for(;x;x-=lowbit(x))ans+=e[x]; 54 return ans; 55 } 56 ll check(int k){ 57 c[0]=0; 58 rep(i,1,n)c[i]=c[i-1]+(a[i]>=k); 59 rep(i,0,n)c[i]=c[i]*2-i,d[i+1]=c[i]; 60 sort(d+1,d+n+2); 61 d[0]=1; 62 rep(i,2,n+1) 63 if(d[i]!=d[d[0]])d[++d[0]]=d[i]; 64 m=d[0]; 65 ll ans=0; 66 rep(i,0,n)c[i]=bin(c[i]); 67 rep(i,0,m)e[i]=0; 68 rep(i,0,n) 69 if(i&1)add(c[i]); 70 else ans+=find(c[i]-1); 71 rep(i,0,m)e[i]=0; 72 rep(i,0,n) 73 if((i&1)==0)add(c[i]); 74 else ans+=find(c[i]-1); 75 return ans; 76 } 77 int main(){ 78 n=read();k=read(); 79 rep(i,1,n)a[i]=read(),b[i]=a[i]; 80 sort(b+1,b+n+1); 81 b[0]=1; 82 rep(i,2,n) 83 if(b[i]!=b[b[0]])b[++b[0]]=b[i]; 84 int l=1,r=b[0]; 85 while(l<r){ //二分 86 int mid=(l+r)/2+1; 87 ll tt=check(b[mid]); 88 if(tt==k){ 89 cout<<b[mid]<<endl; 90 return 0; 91 } 92 if(check(b[mid])>k)l=mid; 93 else r=mid-1; 94 } 95 cout<<b[l]<<endl; 96 return 0; 97 }
第三题弃疗:)
Part2今日专题--二分+贪心(今天主要是通过一些题目来讲的算法)
- 二分大法(为什么要学二分:不断缩小边界,直到求出答案)
-
poj2976:二分答案k,看有没有一种方案使其存在。二分k
-
poj2728:二分答案,花费总和,收益总和>=这个答案。
总花费/总收益>=0 -->跑一遍最大生成树
-
poj3621:找到一个环,使这个环上的边权>0
首先把所有点加入队列(开始均为0),跑SPFA,最后的效果:如果有一个点进入SPFA 超过m次,则结束,存在负权圈(正权圈权的相反数)
-
第k大区间3:统计有多少区间,他的众数出现的次数>t(当前二分值).即存不存在一个数次数大于等于t
O(n^3):枚举左右边界,扫一遍这个区间,每出现一个数i,就把它扔到s[i]这个桶里,即s[i]++;结束后可以求出最大。(桶排序)
枚举右端点r,看有多少个左端点是合法的。左端点要满足的性质:存在单调性,2~5合法,1~5也合法。因此左端点的数量是1~i
首先让l=0.r从1~n扫,找到上一个r[i]出现的位置,更新l,此时l~r都是合法的。以此类推。假如最后得到的l为4,那么当l为1~4时,r这个右区间都是合法的
问题:如何找数字x在上t次出现在哪?
以权重为第一关键字,位置为第二关键字排序,最后那个就是数字x最后出现的位置。
-
1. noip2015跳石头:依然是二分。二分最短距离。如果移走<m块石子,说明距离t可以增大。否则减少。
首先把距离小<=t的删掉。这样就找到了第一个距离岸边>t的石头。接着搜。如果又遇到了一个距离<t的,肯定是删掉后面的石子(即这段小于t的距离有两个石子端点,删掉后面那个)。
这样就能得到移除的石子数量,与m比较可以进一步二分。
-
1. noip2010关押罪犯:二分冲突值。用0和1表示它属于那个监狱,有冲突关系说明数字不一样(即相邻监狱)。
一开始先不分配,随便挑一个出来编号为0,把和他矛盾的人编号为1,再把和他矛盾的矛盾的人编号为0……
当出现如图所示情况时,染色无法成功(二分图的判定)
如果不合法,减小二分的冲突值。否则增大。
- 贪心大法
-
石子合并:Huffman树(解决信息编码问题)
【冷知识】:在26个字母中,字母e出现的次数是最多的
2. noi2015荷马史诗:把合并两堆变成合并k堆
3。 阿狸和桃子的游戏:边权分成两半,各加到两个端点上。为了让一个人尽量大,一个人尽量小,让他们一人拿一半,那么边权就消失了。之后从大到小排一下序,一个人拿1357,一个人拿2468就行了。。
4. Usaco2007 Nov Tanning :
如果没有下限:拿最小的那瓶防晒霜,优先满足限制最大的那个奶牛
有下限:对于最小的防晒霜,把所有能用它的奶牛都挑出来,给上限最小(即限制最多)的奶牛用。
5. 特技飞行:最刺激的放两边
贪心题好多都是猜的
6. 矩阵分割:先切代价大的那条。因此可以把权值按从大到小排序,依次切割。
7.“meet in the middle”
- 提一下分块大法:
分块是什么?
分成根号n,每段根号n个数。
分别求出每段的最小值,把最小值找出来,再求最小值。
-
整体二分
倍增(ST表)
F[i][j]记录的是以i为终点,2^j这么长