CSP模拟8
.....给自己考傻了,有点开摆的感觉。
A. Coprime 2
比较的简单,和洛谷的月赛题差不多。
先把质数都筛出来,然后标记 n 个数的质因子。(预处理)
然后把询问的数枚举,查质因子,然后就没了。
复杂度 O(nlog2n).
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #define rint register int const int MAXN=2e6+5; using namespace std; inline int read() { int f=1,x=0; char ch=getchar(); while(ch<'0' || ch>'9') { if(ch=='-') { f=-1; } ch=getchar(); } while(ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } int n,m,tot; int a[MAXN],ans[MAXN],zs[MAXN]; int main() { n=read() , m=read(); for(rint i=1;i<=n;i++) { int x; x=read(); int now=x; for(rint j=2;j*j<=x;j++) { if(now%j==0) { zs[j]=1; while(now%j==0) { now/=j; if(zs[now]) break; } } if(zs[now]) break; } if(now!=1) { zs[now]=1; } } ans[++tot]=1; for(rint i=2;i<=m;i++) { bool flag=1; int now=i; for(int j=2;j*j<=i;j++) { if(now%j==0) { if(zs[j]) { flag=0; break; } while(now%j==0) { now/=j; } } } if(now!=1 && zs[now]) { flag=0; } if(flag==1) { ans[++tot]=i; } } printf("%d\n",tot); for(rint i=1;i<=tot;i++) { printf("%d\n",ans[i]); } return 0; }
B. Dist Max 2
一眼二分,然后考场上不知怎么的,竟然认为二分不行,然后就寄了。
正解确实是二分。
遇事不决先排序先把其按x为关键字从小到大排序,然后就是二分答案。
设当前check的长度为 len,在来两个指针 l 和 r ,保证两指针x的差值>=len,再在指针的两头判断,相当于把数列分为三部分,在左右两部分找答案。
复杂度 O(nlog2n);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #define rint register int const int MAXN=2e6+5; using namespace std; inline int read() { int f=1,x=0; char ch=getchar(); while(ch<'0' || ch>'9') { if(ch=='-') { f=-1; } ch=getchar(); } while(ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } int n,m,tot; int a[MAXN],ans[MAXN],zs[MAXN]; int main() { n=read() , m=read(); for(rint i=1;i<=n;i++) { int x; x=read(); int now=x; for(rint j=2;j*j<=x;j++) { if(now%j==0) { zs[j]=1; while(now%j==0) { now/=j; if(zs[now]) break; } } if(zs[now]) break; } if(now!=1) { zs[now]=1; } } ans[++tot]=1; for(rint i=2;i<=m;i++) { bool flag=1; int now=i; for(int j=2;j*j<=i;j++) { if(now%j==0) { if(zs[j]) { flag=0; break; } while(now%j==0) { now/=j; } } } if(now!=1 && zs[now]) { flag=0; } if(flag==1) { ans[++tot]=i; } } printf("%d\n",tot); for(rint i=1;i<=tot;i++) { printf("%d\n",ans[i]); } return 0; }
C. Count Multiset
考试时写了一个四维的dp方程,给我自己惊呆了。不过没写就是了。
和CSP模拟7的T3挺像的,首先不考虑m的限制,
设 fi,j 表示分成了 i 个数,总和为 j ,列出一个状态转移方程(也就是构造一个升序序列):
fi,j=fi-1,j-1+fi,j-i;
对于 fi-1,j-1,相当于在数列前填一个1;
对于 fi,j-i,相当于把所有数抬高1;
然后再考虑 m 的限制,也就是1不能随便加了,那就容斥掉 1的个数超过m的方案数;
即:
fi,j=fi-1,j-1+fi,j-i-fi-(m+1),j-i
然后就无了;
复杂度 O(n2);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> const int MAXN=5010; const int mod=998244353; using namespace std; int set; inline int read() { int f=1,x=0; char ch=getchar(); while(ch>'9' or ch<'0') { if(ch=='-') { f=-1; } ch=getchar(); } while(ch>='0' and ch<='9') { x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } return f*x; } int n,m,ans; int dp[MAXN][MAXN]; int main() { n=read() , m=read(); dp[0][0]=1; for(int i=1;i<=n;i++) { if(i<=m) { dp[i][i]=1; } else { break; } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { dp[i][j]=dp[i-1][j-1]; if(j>=i) { dp[i][j]+=dp[i][j-i]; } if(i>=m+1 and j>=i) { dp[i][j]-=dp[i-m-1][j-i]; dp[i][j]%=mod; } dp[i][j]%=mod; } } for(int i=1;i<=n;i++) { printf("%d\n",dp[i][n]%mod); } return 0;#include <iostream> #include <cstdio> const int MAXN=5010; const int mod=998244353; using namespace std; int set; inline int read() { int f=1,x=0; char ch=getchar(); while(ch>'9' or ch<'0') { if(ch=='-') { f=-1; } ch=getchar(); } while(ch>='0' and ch<='9') { x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } return f*x; } int n,m,ans; int dp[MAXN][MAXN]; int main() { n=read() , m=read(); dp[0][0]=1; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { dp[i][j]+=dp[i-1][j-1]; if(j>=i) { dp[i][j]+=dp[i][j-i]; } if(i>=m+1 and j>=i) { dp[i][j]-=dp[i-m-1][j-i]; dp[i][j]%=mod; } dp[i][j]%=mod; } } for(int i=1;i<=n;i++) { printf("%d\n",dp[i][n]%mod); } return 0; }
至于T4,摆了摆了,有时间再写。