首页 > 代码库 > vijos国庆节模拟赛之繁星春水
vijos国庆节模拟赛之繁星春水
A.闪烁的繁星
题目:https://vijos.org/p/1881
题解:貌似做过小白逛公园或者序列操作都可以秒出吧,就是pushup函数比较麻烦,不过仔细想一想就知道了。
代码:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set>10 #include<queue>11 #include<string>12 #define maxn 250000+151013 #define maxm 500+10014 #define eps 1e-1015 #define ll long long16 #define pa pair<int,int>17 #define for0(i,n) for(int i=0;i<=(n);i++)18 #define for1(i,n) for(int i=1;i<=(n);i++)19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)21 #define mod 100000000722 using namespace std;23 inline int read()24 {25 int x=0,f=1;char ch=getchar();26 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}27 while(ch>=‘0‘&&ch<=‘9‘){x=10*x+ch-‘0‘;ch=getchar();}28 return x*f;29 }30 int n,m;31 struct seg{int l,r,ls,rs,lx,rx,mx;}t[4*maxn];32 void build(int k,int l,int r)33 {34 t[k].l=l;t[k].r=r;t[k].lx=t[k].rx=t[k].mx=t[k].ls=t[k].rs=1;35 if(l==r)return;36 int mid=(l+r)>>1;37 build(k<<1,l,mid);build(k<<1|1,mid+1,r);38 }39 void pushup(int k)40 {41 int l=k<<1,r=k<<1|1,mid=(t[k].l+t[k].r)>>1;42 t[k].ls=t[l].ls;t[k].rs=t[r].rs;43 t[k].lx=t[l].lx;44 t[k].rx=t[r].rx;45 t[k].mx=max(t[l].mx,t[r].mx);46 if(t[l].rs!=t[r].ls)47 {48 t[k].mx=max(t[k].mx,t[l].rx+t[r].lx);49 if(t[l].mx==mid-t[k].l+1)t[k].lx=max(t[k].lx,t[l].mx+t[r].lx);50 if(t[r].mx==t[k].r-mid)t[k].rx=max(t[k].rx,t[r].mx+t[l].rx);51 }52 //cout<<t[k].l<<‘ ‘<<t[k].r<<‘ ‘<<t[k].ls<<‘ ‘<<t[k].rs<<‘ ‘<<t[k].lx<<‘ ‘<<t[k].rx<<‘ ‘<<t[k].mx<<endl; 53 }54 void change(int k,int x)55 {56 int l=t[k].l,r=t[k].r,mid=(l+r)>>1;57 if(l==r){t[k].rs=1-t[k].rs;t[k].ls=t[k].rs;return;}58 if(x<=mid)change(k<<1,x);else change(k<<1|1,x);59 pushup(k);60 }61 int main()62 {63 freopen("input.txt","r",stdin);64 freopen("output.txt","w",stdout);65 n=read();m=read();66 build(1,1,n);67 while(m--)change(1,read()),printf("%d\n",t[1].mx);68 return 0;69 }
B.石阶上的砖
题目:https://vijos.org/p/1882
题解:这种题我居然没有做出来T_T
正解是把每个数减去它的相对高度之后降问题转化为一个单变量绝对值和的最小值,显然是中位数。。。
为何我考试的时候以为是神题就放弃了。。。
以后碰到带绝对值的就往中位数想!
代码:(考场上的sb骗分)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set>10 #include<queue>11 #include<string>12 #define inf 100000000000000013 #define maxn 50000014 #define maxm 500+10015 #define eps 1e-1016 #define ll long long17 #define pa pair<int,int>18 #define for0(i,n) for(int i=0;i<=(n);i++)19 #define for1(i,n) for(int i=1;i<=(n);i++)20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)22 #define mod 100000000723 using namespace std;24 inline ll read()25 {26 ll x=0,f=1;char ch=getchar();27 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}28 while(ch>=‘0‘&&ch<=‘9‘){x=10*x+ch-‘0‘;ch=getchar();}29 return x*f;30 }31 ll n,ans,a[2][maxn];32 ll f(ll x){return x>0?x:-x;}33 inline ll check(ll x)34 {35 ll t=0;36 for0(i,1)37 for1(j,n)38 t+=f(a[i][j]-(x+f(j-(n+1)/2)));39 return t;40 }41 int main()42 {43 freopen("input.txt","r",stdin);44 freopen("output.txt","w",stdout);45 n=read();46 for0(i,1)47 for1(j,n)48 a[i][j]=read();49 ans=inf; 50 for0(i,1)51 for1(j,n)52 ans=min(ans,check(a[i][j]));53 printf("%lld\n",ans); 54 return 0;55 }
代码:(正解)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set>10 #include<queue>11 #include<string>12 #define inf 100000000013 #define maxn 100000014 #define maxm 500+10015 #define eps 1e-1016 #define ll long long17 #define pa pair<int,int>18 #define for0(i,n) for(int i=0;i<=(n);i++)19 #define for1(i,n) for(int i=1;i<=(n);i++)20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)22 #define mod 100000000723 using namespace std;24 inline ll read()25 {26 ll x=0,f=1;char ch=getchar();27 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}28 while(ch>=‘0‘&&ch<=‘9‘){x=10*x+ch-‘0‘;ch=getchar();}29 return x*f;30 }31 ll n,a[2*maxn];32 inline ll f(ll x){return x>0?x:-x;}33 int main()34 {35 freopen("input.txt","r",stdin);36 freopen("output.txt","w",stdout);37 n=read();38 for1(i,n)a[i]=read()-f(i-(n+1)/2);39 for1(i,n)a[n+i]=read()-f(i-(n+1)/2);40 sort(a+1,a+2*n+1);41 ll ans=0;42 for1(i,2*n)ans+=f(a[i]-a[n]);43 printf("%lld\n",ans);44 return 0;45 }
C.月光的魔法
题目:https://vijos.org/p/1883
题解:这题比较有意思,考场上大部分时间都在想这题。
每个圆本来只能增加1个平面
会出现更多 是因为一些圆首尾相接把一个大圆割成了两部分
先把圆转化为线段
找出每个圆的第一个祖先
意思就是 完全包含而又最小的圆
然后按左端点递增,左端点相同则右端点越远越优先排序
然后我yy了一个dfs,是这样的
1 void dfs(int x)2 {3 while(m<=n&&a[m].y<=a[x].y)4 {5 fa[m]=x;6 m++;7 dfs(m-1);8 }9 }
因为右端点比x小,而且左端点在x右边的圆一定被x完全包含,而我们只需要一级,所以把这个过程递归下去。
然后就可以求出每个点i的fa[i]了
然后这样扫一遍
1 for1(i,n)s[fa[i]]+=a[i].y-a[i].x;2 int ans=n+1;3 for1(i,n)if(s[i]==a[i].y-a[i].x)ans++;
此题就over了。
不知神犇们还有什么更好的方法,我感觉我的方法比较猎奇。。。
代码:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set>10 #include<queue>11 #include<string>12 #define inf 10000000000013 #define maxn 50000014 #define maxm 500+10015 #define eps 1e-1016 #define ll long long17 #define pa pair<int,int>18 #define for0(i,n) for(int i=0;i<=(n);i++)19 #define for1(i,n) for(int i=1;i<=(n);i++)20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)22 #define mod 100000000723 using namespace std;24 inline ll read()25 {26 ll x=0,f=1;char ch=getchar();27 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}28 while(ch>=‘0‘&&ch<=‘9‘){x=10*x+ch-‘0‘;ch=getchar();}29 return x*f;30 }31 struct rec{ll x,y;}a[maxn];32 int n,m,ans,fa[maxn];33 ll s[maxn];34 inline bool cmp(rec a,rec b)35 {36 return a.x<b.x||(a.x==b.x&&a.y>b.y);37 }38 void dfs(int x)39 {40 while(m<=n&&a[m].y<=a[x].y)41 {42 fa[m]=x;43 m++;44 dfs(m-1);45 }46 }47 int main()48 {49 freopen("input.txt","r",stdin);50 freopen("output.txt","w",stdout);51 n=read();52 for1(i,n)53 {54 ll x=read(),y=read();55 a[i].x=x-y;a[i].y=x+y;56 }57 sort(a+1,a+n+1,cmp);58 m=1;59 a[0].y=inf;60 dfs(0);61 for1(i,n)s[fa[i]]+=a[i].y-a[i].x;62 int ans=n+1;63 for1(i,n)if(s[i]==a[i].y-a[i].x)ans++;64 printf("%d\n",ans);65 return 0;66 }
D.诗情
题目:https://vijos.org/p/1884
题解:考场上只会2^m*n的递推,简直sb。。。MLE+TLE
因为昨天刚做了一道类似的T_T
话说暴力枚举每个位置上的数也比这个快把T_T
然后搬运一份正解:
(用meet-in-the-middle的思想。先一遍dfs暴力求出长度为[n/2]的情况下([x]表示对x下取整),某一hash值f有多少个串与之对应。
求出33对于2^m的逆元inv,然后反向dfs后半段。可以秒出。)
竟如此简单。。。 话说在黑书上看过这种思想啊,当时为什么没想出来T_T
有几个细节需注意:
1)因为gcd(33,1<<m)==1,所以33对1<<m有逆元
2)33模1<<m的逆元=power(33,phi(1<<m)-1)=power(33,(1<<(m-1))-1)
3)因为 a xor b xor b=a,所以反向搜的时候直接异或就可以,这应该是此题的特殊之处吧,
代码:(考场上暴力DP)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set>10 #include<queue>11 #include<string>12 #define inf 100000000013 #define maxn 105000014 #define maxm 500+10015 #define eps 1e-1016 #define ll long long17 #define pa pair<int,ll>18 #define for0(i,n) for(int i=0;i<=(n);i++)19 #define for1(i,n) for(int i=1;i<=(n);i++)20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)22 #define mod 100000000723 using namespace std;24 inline int read()25 {26 int x=0,f=1;char ch=getchar();27 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}28 while(ch>=‘0‘&&ch<=‘9‘){x=10*x+ch-‘0‘;ch=getchar();}29 return x*f;30 }31 ll n,k,m,sum,cnt,mx,f[11][maxn];32 int main()33 {34 freopen("input.txt","r",stdin);35 freopen("output.txt","w",stdout);36 n=read();k=read();m=read();37 f[0][0]=1;sum=1;mx=1<<m;38 for1(i,n)39 {40 cnt=0;41 for0(j,mx-1)42 if(f[i-1][j])43 {44 cnt++;45 for1(k,26)46 f[i][((j*33)^k)%mx]+=f[i-1][j];47 if(cnt==sum)break; 48 }49 sum*=26;50 }51 cout<<f[n][k]<<endl;52 return 0;53 }
代码:(正解)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set>10 #include<queue>11 #include<string>12 #define inf 100000000013 #define maxn 500+10014 #define maxm 500+10015 #define eps 1e-1016 #define ll long long17 #define pa pair<int,int>18 #define for0(i,n) for(int i=0;i<=(n);i++)19 #define for1(i,n) for(int i=1;i<=(n);i++)20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)22 #define mod 100000000723 using namespace std;24 inline ll read()25 {26 ll x=0,f=1;char ch=getchar();27 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}28 while(ch>=‘0‘&&ch<=‘9‘){x=10*x+ch-‘0‘;ch=getchar();}29 return x*f;30 }31 ll n,k,m,inv,res,mx1,mx2,sum[1<<25];32 inline void dfs(int dep,ll s)33 {34 if(dep==mx1)sum[s%m]++;35 else for1(i,26)dfs(dep+1,((s<<5)+s^i)%m);36 }37 inline void dfs2(int dep,ll s)38 {39 if(dep==mx2)res+=sum[s%m];40 41 else for1(i,26)dfs2(dep+1,((s^i)*inv)%m);42 }43 inline ll power(ll x,ll y)44 {45 ll t=1;46 for(;y;y>>=1,x=(x*x)%m)47 if(y&1)t=(t*x)%m;48 return t;49 }50 int main()51 {52 freopen("input.txt","r",stdin);53 freopen("output.txt","w",stdout);54 n=read();k=read();m=1<<read();inv=power(33,(m>>1)-1);55 mx1=(n+1)>>1;mx2=n>>1;dfs(0,0);dfs2(0,k);56 cout<<res<<endl;57 return 0;58 }
以后一定要多动脑想一想,不要误以为t2这种sb题不可做!!!
vijos国庆节模拟赛之繁星春水