筑梯杯郑州轻工业大学第十七届程序设计大赛题解(12/12)
比赛链接:https://ac.nowcoder.com/acm/contest/106899
ANo idea
队友写的,模拟题,遇到2024修改一下即可
#include<bits/stdc++.h> #define maxn 1000010 using namespace std; int T,n; char s[maxn]; int main(){ //freopen(".in","r",stdin); //freopen(".out","w",stdout); scanf("%d",&T); while(T--){ scanf("%s",s+1);n=strlen(s+1); for(int i=1;i<=n;i++){ if(s[i]=='2'&&s[i+1]=='0'&&s[i+2]=='2'&&s[i+3]=='4')s[i+3]++,i+=3; } for(int i=1;i<=n;i++)printf("%c",s[i]),s[i]=0; printf("\n"); } return 0; }
B超椭圆
队友写的
这题推式子非常难,但是我们打的网络赛,队友百度了一下式子,代入即可
#include<bits/stdc++.h> using namespace std; double solve(double a,double b,double n){ if(n<=0)return 0.0; double a1=std::tgamma(1.0+1.0/n); double a2=std::tgamma(1.0+2.0/n); double area=4.0*a*b*(a1*a1)/a2; return area; } int main(){ double a,b,n; scanf("%lf%lf%lf",&a,&b,&n); printf("%.7lf\n",solve(a,b,n)); return 0; }
正经去写应该微元法做积分
C简单题
使用了类似字典树和基数排序的思想
考虑第一位选某个值有多少个,比如1 2 3 ,第一位选1的有三个,第一位选2的有两个,第一位选3的有一个。看k的大小可以得知第一位的值,接下来继续看第二位,接下来继续看第三位。直到k超过了全体的方案数,说明这一位留空,开始输出即可。
例如k=6,当确定第一位选1后,问题转变成了123,12,1里面选第3大。在第一位选1的三种方案里,有2种方案是第二位为2,1种方案是第二位为空,发现k>2,因此可以确定第二位为空,输出1即可结束。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5010,mod=998244353;//1e9+7; ll read(){ll x;scanf("%lld",&x);return x;} ll quick(ll a,ll b){ll t=1;while(b){if(b&1)t=t*a%mod;b=b/2;a=a*a%mod;}return t;} int lowbit(int x){return x&(-x);} int n,k,a[N]; vector<int>b; struct node { int l,r,len; }; int sum[N]; vector<int>o[2]; int main() { n=read();k=read(); for(int i=1;i<=n;i++) { a[i]=read(); b.push_back(a[i]); o[0].push_back(i); } sort(b.begin(),b.end()); b.erase(unique(b.begin(),b.end()),b.end()); for(int i=1;i<=n;i++) a[i]=lower_bound(b.begin(),b.end(),a[i])-b.begin()+1; for(int ans=0;;ans++) { memset(sum,0,sizeof(sum)); for(auto l:o[ans%2]) { int r=l+ans; if(r<=n) sum[a[r]]+=n-l+1-ans; else sum[n+1]+=1; } int pos=0; for(int i=n;i>=1;i--) { if(sum[i]>=k) { pos=i; break;//答案在这里 } k-=sum[i]; } if(pos==0) { for(auto l:o[ans%2]) { for(int i=l;i<l+ans;i++) cout<<b[a[i]-1]<<' '; exit(0); } } int nxt=1-ans%2; o[nxt].clear(); for(auto l:o[ans%2]) { int r=l+ans; if(a[r]==pos) { o[nxt].push_back(l); } } } }
D双影奇境
队友写的
想要互相到达,首先需要(x+y)%2=(x+y)%2,其次需要在同一个联通块里
其次还有一种特殊情况是不能闪转腾挪的情况:比如一个人旁边就是终点,周围全是障碍,这个时候必须一步到位。
#include<bits/stdc++.h> #define maxn 510 #define maxm 300010 using namespace std; int n,m,q,a1,a2,a3,a4,a5,a6,fa[maxm],dis[maxm]; char s[maxn][maxn]; int z(int q1,int q2){return (q1-1)*m+q2;} void find(int x){ if(fa[x]==x)return; find(fa[x]); dis[x]=(dis[x]+dis[fa[x]])%2; fa[x]=fa[fa[x]]; return; } void he(int x,int y){ find(x),find(y); int f1=fa[x],f2=fa[y]; if(f1!=f2)fa[f2]=f1,dis[f2]=dis[y]^dis[x]^1; return; } int sb1(int x1,int y1,int x2,int y2){ if(x1==x2&&y1==y2-1)return 1; if(x1==x2&&y1==y2+1)return 1; if(y1==y2&&x1==x2-1)return 1; if(y1==y2&&x1==x2+1)return 1; return 0; } int sb2(int x1,int y1,int x2,int y2){ if(x1-1!=x2&&s[x1-1][y1]=='.')return 0; if(x1+1!=x2&&s[x1+1][y1]=='.')return 0; if(y1-1!=y2&&s[x1][y1-1]=='.')return 0; if(y1+1!=y2&&s[x1][y1+1]=='.')return 0; return 1; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) fa[z(i,j)]=z(i,j); for(int i=1;i<=n;i++)scanf("%s",s[i]+1); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(s[i][j]=='#')continue; if(i!=1&&s[i-1][j]!='#')he(z(i-1,j),z(i,j)); if(j!=1&&s[i][j-1]!='#')he(z(i,j-1),z(i,j)); } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ find(z(i,j)); //cout<<dis[z(i,j)]<<" "; }//cout<<endl; } scanf("%d",&q); while(q--){ scanf("%d%d",&a1,&a2);scanf("%d%d",&a3,&a4);scanf("%d%d",&a5,&a6); if(sb1(a1,a2,a5,a6)&&sb1(a3,a4,a5,a6)){printf("Yes\n");continue;} if(sb1(a1,a2,a5,a6)&&sb2(a1,a2,a5,a6)){printf("No\n");continue;} if(sb1(a3,a4,a5,a6)&&sb2(a3,a4,a5,a6)){printf("No\n");continue;} find(z(a1,a2)),find(z(a3,a4)),find(z(a5,a6)); int f1=fa[z(a1,a2)],f2=fa[z(a3,a4)],f3=fa[z(a5,a6)]; //cout<<f1<<" "<<dis[z(a1,a2)]<<" "<<dis[z(a3,a4)]<<endl; if(f1!=f2||f2!=f3)printf("No\n"); else{ if(dis[z(a1,a2)]==dis[z(a3,a4)])printf("Yes\n"); else printf("No\n"); } } return 0; }
E小刻与奇怪队列
队友写的,看起来是个splay?
#include<bits/stdc++.h> #define maxn 100010 #define inf 2147483647 using namespace std; int sum; struct node{int l,r,z,c,si,s;}a[maxn]; int _new(int x){a[++sum].z=x;a[sum].s=rand();a[sum].c=a[sum].si=1;return sum;} void update(int x){a[x].si=a[a[x].l].si+a[a[x].r].si+a[x].c;return;} void build(int &root){root=_new(-inf);a[root].r=_new(inf);update(root);return;} void zig(int &p){int q=a[p].l;a[p].l=a[q].r;a[q].r=p;p=q;update(a[p].r);update(p);return;} void zag(int &p){int q=a[p].r;a[p].r=a[q].l;a[q].l=p;p=q;update(a[p].l);update(p);return;} void insert(int &p,int x){if(p==0){p=_new(x);return;}if(a[p].z==x){a[p].c++;update(p);return;}if(x<a[p].z){insert(a[p].l,x);if(a[a[p].l].s>a[p].s)zig(p);}else{insert(a[p].r,x);if(a[a[p].r].s>a[p].s)zag(p);}update(p);return;} void remove(int &p,int x){if(p==0)return;if(a[p].z==x){if(a[p].c>1)a[p].c--;else{if(a[p].l||a[p].r){if(a[p].r==0&&a[a[p].l].s>=a[a[p].r].s)zig(p),remove(a[p].r,x);else zag(p),remove(a[p].l,x);}else p=0;}update(p);return;}if(x<a[p].z)remove(a[p].l,x);else remove(a[p].r,x);update(p);return;} int getz(int p,int x){if(a[p].si<x)return inf;if(a[a[p].l].si>=x)return getz(a[p].l,x);if(a[a[p].l].si+a[p].c>=x)return a[p].z;return getz(a[p].r,x-a[a[p].l].si-a[p].c);} int root,n,a1,a2,ll=1,rr=0,su=0; map<int,int>mp; int main(){ scanf("%d",&n);build(root); while(n--){ scanf("%d",&a1); if(a1==1){ scanf("%d",&a2); ll--;mp[ll]=a2;insert(root,ll);su++; } else if(a1==2){ scanf("%d",&a2); rr++;mp[rr]=a2;insert(root,rr);su++; } else{ int fz=0; if(su%2==0)fz=su/2; else fz=su/2+1; fz=getz(root,fz+1); printf("%d\n",mp[fz]); remove(root,fz);su--; } } return 0; }
F你好多宝宝,你开幼儿园算了
构造题
最好是给最大边替换成0,这样就需要在最大边的外面找俩点连边
设最大边的端点是x和y,由于n>2,因此不可能xy都是叶子,度数都为1。不妨设x的度数大于1,则可以输出y和x的任意一个非y邻接点
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=100010,mod=998244353;//1e9+7; ll read(){ll x;scanf("%lld",&x);return x;} ll quick(ll a,ll b){ll t=1;while(b){if(b&1)t=t*a%mod;b=b/2;a=a*a%mod;}return t;} int lowbit(int x){return x&(-x);} int n; struct node { int x,y,w; friend bool operator <(node a,node b) { return a.w<b.w; } }e[N]; set<int>o[N]; void work() { n=read(); for(int i=1;i<=n;i++) o[i].clear(); for(int i=1;i<n;i++) { e[i].x=read(); e[i].y=read(); e[i].w=read(); o[e[i].x].insert(e[i].y); o[e[i].y].insert(e[i].x); } sort(e+1,e+n); if(o[e[n-1].x].size()==1) swap(e[n-1].x,e[n-1].y); o[e[n-1].x].erase(e[n-1].y); cout<<e[n-1].y<<' '<<*o[e[n-1].x].begin()<<' '<<0<<'\n'; } int main() { //freopen(".in","r",stdin); //freopen(".out","w",stdout); for(int t=read();t;t--) work(); }
G数组笑传之查查表
队友写的,好像也写了个splay?
#include<bits/stdc++.h> #define maxn 100010 #define inf 2147483647 using namespace std; int sum; struct node{int l,r,z,c,si,s;}a[maxn]; int _new(int x){a[++sum].z=x;a[sum].s=rand();a[sum].c=a[sum].si=1;return sum;} void update(int x){a[x].si=a[a[x].l].si+a[a[x].r].si+a[x].c;return;} void build(int &root){root=_new(-inf);a[root].r=_new(inf);update(root);return;} void zig(int &p){int q=a[p].l;a[p].l=a[q].r;a[q].r=p;p=q;update(a[p].r);update(p);return;} void zag(int &p){int q=a[p].r;a[p].r=a[q].l;a[q].l=p;p=q;update(a[p].l);update(p);return;} void insert(int &p,int x){if(p==0){p=_new(x);return;}if(a[p].z==x){a[p].c++;update(p);return;}if(x<a[p].z){insert(a[p].l,x);if(a[a[p].l].s>a[p].s)zig(p);}else{insert(a[p].r,x);if(a[a[p].r].s>a[p].s)zag(p);}update(p);return;} int getrank(int p,int x){if(p==0)return 0;if(a[p].z==x)return a[a[p].l].si;if(x<a[p].z)return getrank(a[p].l,x);return a[a[p].l].si+a[p].c+getrank(a[p].r,x);} int root,n,a1[maxn],a2[maxn]; int main(){ scanf("%d",&n);build(root); for(int i=1;i<=n;i++)scanf("%d",&a1[i]),insert(root,a1[i]); for(int i=1;i<=n;i++)scanf("%d",&a2[i]); for(int i=1;i<=n;i++){ int ans=getrank(root,a1[i])-1; if(i!=1)printf(" "); if(2*a2[i]<=ans)printf("0"); else printf("%d",a2[i]*2-ans); } printf("\n"); return 0; }
H ARK no NIGHTS
模拟题
考虑写一个暴力,得到某个时间点的总毫秒数。则有没有超过8小时只需要看看总毫秒数的差值有没有超过8小时的总毫秒数
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=200010,mod=998244353;//1e9+7; ll read(){ll x;scanf("%lld",&x);return x;} ll quick(ll a,ll b){ll t=1;while(b){if(b&1)t=t*a%mod;b=b/2;a=a*a%mod;}return t;} int lowbit(int x){return x&(-x);} int flag[30]; ll ask(int a,int b,ll c,int d,int e,int f) { ll t=f+e*60+d*60*60; for(int i=2000;i<a;i++) for(int j=1;j<=12;j++) if(flag[j]) c=c+31; else if(j==2) { if(i%400==0||i%4==0&&i%100!=0) c=c+29; else c=c+28; } else c=c+30; for(int i=a;i<=a;i++) for(int j=1;j<b;j++) if(flag[j]) c=c+31; else if(j==2) { if(i%400==0||i%4==0&&i%100!=0) c=c+29; else c=c+28; } else c=c+30; return c*24*60*60ll+t; } void work() { int a,b,c,d,e,f; scanf("%d-%d-%dT%d:%d:%d",&a,&b,&c,&d,&e,&f); ll tt=ask(a,b,c,d,e,f); scanf("%d-%d-%dT%d:%d:%d",&a,&b,&c,&d,&e,&f); tt=ask(a,b,c,d,e,f)-tt; if(tt>=ask(0,0,0,8,0,0)) cout<<"Yes\n"; else cout<<"No\n"; } int main() { flag[1]=flag[3]=flag[5]=flag[7]=flag[8]=flag[10]=flag[12]=1; //freopen(".in","r",stdin); //freopen(".out","w",stdout); for(int t=read();t;t--) work(); }
I #define int bigint
众所周知,a%b=a-a/b*b
因此a/b=(a-a%b)/b
a%b很容易做,是%b意义下的快速幂。得到0~b-1范围内的a%b,再求一下%1e9+7下的a的值,两者相减,再除以b的%1e9+7下的逆元即可得到答案
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=200010,mod=1e9+7; ll read(){ll x;scanf("%lld",&x);return x;} ll quick(ll a,ll b){ll t=1;while(b){if(b&1)t=t*a%mod;b=b/2;a=a*a%mod;}return t;}int lowbit(int x){return x&(-x);} ll quick(ll a,ll b,ll modd) { ll t=1; while(b) { if(b&1) t=t*a%modd; b=b/2; a=a*a%modd; } return t; } ll n,p[N],e[N],b,ans; ll ask() { ll t=1; for(int i=1;i<=n;i++) { t=t*quick(p[i],e[i])%mod; } return t; } void work() { n=read(); for(int i=1;i<=n;i++) { p[i]=read(); e[i]=read(); } b=read(); ans=1; for(int i=1;i<=n;i++){ ans=ans*quick(p[i],e[i],b)%b; } ans=(ask()-ans)*quick(b,mod-2)%mod; ans=(ans+mod)%mod; cout<<ans; } int main() { //freopen(".in","r",stdin); //freopen(".out","w",stdout); // for(int t=read();t;t--) work(); }
J C 属性大爆发
大模拟
首先可以用dxdy分别表示xy的运动方向,则每次反弹都是相同的dx=-dx,dy=-dy
然后注意细节,多构造测试点调试即可
// Powered by CP Editor (https://cpeditor.org) #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1010,mod=998244353;//1e9+7; ll read(){ll x;scanf("%lld",&x);return x;} ll quick(ll a,ll b){ll t=1;while(b){if(b&1)t=t*a%mod;b=b/2;a=a*a%mod;}return t;} int lowbit(int x){return x&(-x);} int n,m,t; char s[N][N]; int xx,yy,dx,dy,k; int main() { n=read();m=read();t=read(); for(int i=1;i<=n;i++) { scanf("%s",s[i]+1); for(int j=1;j<=m;j++) if(s[i][j]=='O') xx=i,yy=j,s[i][j]='.'; } for(int j=0;j<=m+1;j++) s[0][j]=s[n+1][j]='#'; for(int i=1;i<=n;i++) s[i][0]=s[i][m+1]='.'; k=read(); for(int i=1;i<=k;i++) { char c; cin>>c; if(c=='U') dx-=1; else if(c=='R') dy+=1; else if(c=='D') dx+=1; else dy-=1; } for(int i=1,num=1;i<=t&&num<=50000000;i++,num++) { if(dx&&dy)//45° { if(s[xx][yy+dy]=='#'||s[xx+dx][yy]=='#')//过不去,需要反弹 { i--; if(s[xx][yy+dy]=='#'){ dy=-dy; if(s[xx][yy+dy]=='#'){ dy=0; } } if(s[xx+dx][yy]=='#'){ dx=-dx; if(s[xx+dx][yy]=='#'){ dx=0; } } } else if(s[xx+dx][yy+dy]=='#')//虽然旁边没有,但是这里也有 { i--; dx=-dx; dy=-dy; } else //都没有,过去 { xx+=dx; yy+=dy; } } else//横着走 { if(s[xx+dx][yy+dy]=='.') { xx+=dx; yy+=dy; } else { i--; dx=-dx; dy=-dy; } } if(yy==0){ cout<<"Lose"; exit(0); } if(yy==m+1) { cout<<"Win"; exit(0); } if(dx==0&&dy==0) break; } cout<<'('<<xx<<", "<<yy<<')'; }
K 计算机的末路
状压dp+最短路
共有2k+1个特殊点,先跑21次最短路
接下来状压:f[S][j]表示过特殊点的状态为S,停在了j号特殊点的最短距离
对于每份订单,必须先去取餐点再去送餐点,因此需要在送餐点转移的时候格外注意有没有去过取餐点
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=100010; int read(){int x;scanf("%d",&x);return x;} int n,m,k,p; int vis[N],nod[N],cnt,s[12],t[12]; ll d[22][N]; vector<pair<int,int>>e[N]; void insert(int x) { // if(pos[x]) // return ; nod[cnt]=x;//rk和编号映射 // pos[x]=cnt;//编号和rk映射 cnt++; } ll f[1<<21][21]; priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>>q; void dij(int x,int rk) { for(int i=1;i<=n;i++) vis[i]=0; d[rk][x]=0; q.push({0,x}); while(q.size()) { x=q.top().second; q.pop(); if(vis[x]) continue; vis[x]=1; for(auto [y,v]:e[x]) { if(d[rk][y]>d[rk][x]+v) { d[rk][y]=d[rk][x]+v; q.push({d[rk][y],y}); } } } } int main() { n=read();m=read();k=read();p=read(); // n=100000;m=100000;k=10;p=3; insert(p); memset(d,0x3f,sizeof(d)); for(int i=1;i<=m;i++) { int x=read(),y=read(),v=read(); // int x=i,y=i+1,v=3; e[x].push_back({y,v}); e[y].push_back({x,v}); } for(int i=1;i<=k;i++) { s[i]=read(),t[i]=read(); // s[i]=rand()%n+1,t[i]=rand()%n+1; insert(s[i]); insert(t[i]); } for(int i=1;i<=cnt;i++) dij(nod[i],i); memset(f,0x3f,sizeof(f)); f[1][0]=0; for(int i=0;i<(1<<cnt);i++) { for(int x=1;x<cnt;x++)//这次要送x { if((i&(1<<x))==0) continue; if(x%2==0&&(i&(1<<(x-1)))==0)//要送这个但是没去过起点 continue; for(int y=0;y<cnt;y++) { if(i&(1<<y)) f[i][x]=min(f[i][x],f[i-(1<<x)][y]+d[x][nod[y]]); } } } ll ans=f[(1<<cnt)-1][0]; for(int i=1;i<cnt;i++) { ans=min(ans,f[(1<<cnt)-1][i]); } cout<<ans; }
L 割方术
输出四个输入数字的gcd即可
// Powered by CP Editor (https://cpeditor.org) #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=200010,mod=998244353;//1e9+7; ll read(){ll x;scanf("%lld",&x);return x;} ll quick(ll a,ll b){ll t=1;while(b){if(b&1)t=t*a%mod;b=b/2;a=a*a%mod;}return t;} int lowbit(int x){return x&(-x);} void work() { ll n=read(),m=read(),N=read(),M=read(); cout<<__gcd(__gcd(n,m),__gcd(N,M))<<'\n'; } int main() { //freopen(".in","r",stdin); //freopen(".out","w",stdout); for(int t=read();t;t--) work(); }

浙公网安备 33010602011771号