高二&高一&初三模拟赛14 总结
来源:互联网 发布:日本轻小说软件 编辑:程序博客网 时间:2024/04/29 04:58
T1:完全平方数(SMOJ2236)
题目分析:一道莫比乌斯反演的例题……
记f(k)表示1~k中没有完全平方数因子的数的个数,很明显f单调不降,于是可以二分答案。那么我们如何求f(k)呢?我们可以枚举平方因子
试一试就会知道当
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=50010;int miu[maxn];bool vis[maxn];int prime[maxn];int cur=0;int t,k;void Make(){ miu[1]=1; for (int i=2; i<maxn; i++) { if (!vis[i]) miu[i]=-1,prime[++cur]=i; for (int j=1; j<=cur && i*prime[j]<maxn; j++) { int k=i*prime[j]; vis[k]=true; if (i%prime[j]) miu[k]=-miu[i]; else { miu[k]=0; break; } } }}int Get(int x){ int temp=0; for (int i=1; i*i<=x; i++) temp+=miu[i]*(x/(i*i)); return temp;}int Binary(){ int L=1,R=k<<1; while (L+1<R) { long long mid=(long long)L+(long long)R; mid>>=1; if ( Get(mid)<k ) L=mid; else R=mid; } return R;}int main(){ freopen("2236.in","r",stdin); freopen("2236.out","w",stdout); Make(); scanf("%d",&t); while (t--) { scanf("%d",&k); int ans=Binary(); printf("%d\n",ans); } return 0;}
T2:字符染色(SMOJ2237)
题目分析:还记得省赛前SemiWaker跟我们讲补偿转移DP,听得我半懵半懂,现在遇见一题,才真正领悟了些许。
我们不妨记f[i][j][s]表示现在处理到字符串的第i位,其中第i位填的是j(j=0代表B,j=1代表W),而且状态为s(s=0代表之前还没有出现连续k个B,s=1表示之前出现了连续k个B,但还没有连续k个W,s=2代表之前已有连续k个B,连续k个W)。那么
但这样明显是不对的,就拿s=0为例,我们要减去到第i-k+1位~第i位才刚好组成了连续k个B的情况。即当字符串的第i-k+1~i位没有W的时候(这个可以用前缀和判断),f[i][0][0]要减去f[i-k][1][0],f[i][0][1]要相对应地加上这个值。那么为什么要求第i-k位一定是W呢?因为如果第i-k位是B,第i-k~i-1位就构成了连续的k个B,和我们“到第i-k+1位~第i位才刚好组成了连续k个B“的要求不符。这样做时间复杂度
其实这题说是补偿转移有点牵强,用低级的话来说就是容斥原理。然而我考试的时候,以及考完试想了很久都想不出来,最后看了网上的题解才明白,可能我的DP还是太差了。
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=1000100;const long long M=1000000007;typedef long long LL;LL f[maxn][3][2];int b[maxn];int w[maxn];char s[maxn];int n,k;int main(){ freopen("2237.in","r",stdin); freopen("2237.out","w",stdout); scanf("%d%d",&n,&k); scanf("%s",&s); for (int i=0; i<n; i++) { if (s[i]=='B') b[i+1]=1; if (s[i]=='W') w[i+1]=1; } for (int i=2; i<=n; i++) b[i]+=b[i-1],w[i]+=w[i-1]; f[0][0][1]=1; for (int i=1; i<=n; i++) { bool fb=false,fw=false; if (s[i-1]!='W') fb=true; if (s[i-1]!='B') fw=true; if (fb) { for (int j=0; j<=2; j++) f[i][j][0]=(f[i-1][j][0]+f[i-1][j][1])%M; if ( i>=k && w[i]==w[i-k] ) { f[i][0][0]=(f[i][0][0]-f[i-k][0][1]+M)%M; f[i][1][0]=(f[i][1][0]+f[i-k][0][1])%M; } } if (fw) { for (int j=0; j<=2; j++) f[i][j][1]=(f[i-1][j][0]+f[i-1][j][1])%M; if ( i>=k && b[i]==b[i-k] ) { f[i][1][1]=(f[i][1][1]-f[i-k][1][0]+M)%M; f[i][2][1]=(f[i][2][1]+f[i-k][1][0])%M; } } } LL ans=(f[n][2][0]+f[n][2][1])%M; printf("%lld\n",ans); return 0;}
T3:乌鸦喝水(SMOJ2238)
题目分析:一道很简单的模拟题,然而我还是写炸了……
我们先算出每一个水井会在下降多少次之后不能喝,记在一个数组t中。假设乌鸦飞一遍所有水井,会喝x个水井的水,那么所有水井的t值就会全部减去x。x值什么时候会发生变化呢?就是在某一个水井的t值变为0或以下的时候。于是我们按t值对水井排序,然后看一下哪些水井可能在下一轮喝水之后t值降为0或以下(即t值小于当前的x),暴力计算这些水井的是否能在下一轮喝到,以及它t值实际会降到多少。
具体的操作是这样:假设第i个水井到第j个水井可能会在下一轮被喝光(t值小于x),我们将它们按位置从左到右再排序,然后用树状数组查看某个水井左边有几个是t值>=x的(即在这一轮一定会被喝到),并记录一下它左边t值小于x的水井实际喝了几个,然后判断一下它当前的t值是否大于等于上面的两个值之和,是的话就可以喝它。
但像上面那样做并不能保证每一个水井只被操作一遍,如下例:
t={1,1,4,1,4}
所有水井的t值都小于5,于是我们要将它们一起处理,处理完一轮之后t值变为下面这样:
t={-2,-2,1,-2,1}
此时还有两个水井没有喝完。
为什么会出现这种情况呢?因为某些水井当前的t值虽然小于x,但由于另外一些水井实际上并没有被喝,导致所有t值的减小量不足x,它就有可能t值还是大于0。
于是我们没法保证时间复杂度了吗?
不妨假设现在有n个水井一起被处理,其中有x个水井被喝到了水(也就是说有n-x个水井无法再喝)。若
然而kekxy还有一种严格
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=100100;struct data{ int t,id;} b[maxn];int bit[maxn];int d[maxn];int temp[maxn];int num=0;int n,m,X;int Time=0,ans=0;bool Comp1(data x,data y){ return x.t<y.t;}bool Comp2(data x,data y){ return x.id<y.id;}void Add(int x,int v){ while (x<=n) { bit[x]+=v; x+=(x&(-x)); }}int Sum(int x){ int s=0; while (x) { s+=bit[x]; x-=(x&(-x)); } return s;}int main(){ freopen("2238.in","r",stdin); freopen("2238.out","w",stdout); scanf("%d%d%d",&n,&m,&X); for (int i=1; i<=n; i++) scanf("%d",&d[i]); for (int i=1; i<=n; i++) { int a; scanf("%d",&a); b[i].t=(X-d[i])/a+1; b[i].id=i; } sort(b+1,b+n+1,Comp1); for (int i=1; i<=n; i++) { if (b[i].t<=ans) { Add(b[i].id,1); continue; } int x=(b[i].t-ans)/(n-i+1); if (Time+x>=m) { ans+=((m-Time)*(n-i+1)); break; } Time+=x; ans+=(x*(n-i+1)); int j=i; while ( j<n && b[j+1].t-ans<=n-i+1 ) j++; sort(b+i,b+j+1,Comp2); for (int k=i; k<=j; k++) { int w=b[k].id; if ( b[k].t-ans<w-Sum(w) ) temp[++num]=w,Add(w,1); } Time++; ans+=(n-i+1-num); while (num) Add(temp[num],-1),num--; sort(b+i,b+j+1,Comp1); Add(b[i].id,1); } printf("%d\n",ans); return 0;}
总结:这次比赛真的脑抽了,写T3的时候本来写了一句正确的代码,交上去也已经AC了的,结果忽然头脑发热没考虑清楚,以为那句是错的,就把那句改错了……然后第一个点返回0分,一直在不停地调,导致T2草草交了个20分的大暴力就算了,其实T2的50分算法也很容易想的。以后做题的时候要思考谨慎再码代码;另外要多做DP,提高智商。
- 高二&高一&初三模拟赛14 总结
- 高二&高一&初三模拟赛16 总结
- 高二&高一&初三模拟赛15 总结
- 高二&高一&初三模拟赛16 总结
- 高二&高一&初三模拟赛17 总结
- 高二&高一&初三模拟赛18 总结
- 高二&高一&初三模拟赛17 总结
- 高二&高一&初三模拟赛19 总结
- 高二&高一&初三模拟赛20 总结
- 高二&高一&初三模拟赛22 总结
- 高二&高一&初三模拟赛21 总结
- 高二&高一&初三模拟赛22 总结
- 高二&高一&初三模拟赛23 总结
- 高二&高一&初三模拟赛23 总结
- 高二&高一&初三模拟赛24 总结
- 高二&高一&初三模拟赛25 总结
- 高二&高一&初三模拟赛26 总结
- 高二&高一&初三模拟赛24 总结
- Linux---vi/vim复制剪切粘贴以及常用命令小结
- Markdown编辑器使用
- Delete Operation for Two Strings问题及解法
- Nginx下配置网站SSL实现https访问本站就是用的这方法
- Algorithm-week2
- 高二&高一&初三模拟赛14 总结
- 第一周“冒泡”作
- javascript中的私有变量及如何在函数外部引用这些变量
- java web项目优化过程
- 基于RPGMakerMV的JavaScript基础-2
- hbase hive elasticsearch(elsearch) mysql mongodb 技术选型
- 单链表的Java实现
- 数据库中范式的分类和它们之间的转化
- nginx解决前端跨域配置