原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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 */
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 }
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 }