======牛客多校第一场====== 因为事务繁忙、时间紧迫,这里的题解区仅暂存一下通关代码。 有趣的是,过的几个题都是C语言,暂时还没用到C++的STL。 =====D===== 高斯消元板子,含快速幂,没什么内容。 #include #include #define MOD 998244353 long long n,var,equ,pic[256][256],x[256]; long long ans[256]; long long abs(long long x) { return (x>0)?x:-x; } long long QPow(long long bas,long long t) { long long ret=1; for(;t;t>>=1,bas=(bas*bas)%MOD) { if(t&1LL) { ret=(ret*bas)%MOD; } } return ret; } void Gauss() { long long i,j,k,col,maxr; for(k=0,col=0;kabs(pic[maxr][col])) { maxr=i; } } if(k!=maxr) { for(j=col;j=0?l:l+MOD)); } return 0; } =====F===== 本题几乎什么都没用到,却因为max的小问题,WA了非常多次。深表惭愧。 #include #include int main() { int lena,lenb,flag; long long max; char a[100005],b[100005]; while(~scanf("%s%s",a,b)) { lena=strlen(a); lenb=strlen(b); max=2*(lena>lenb?lena:lenb); flag=0; long long i; for(i=0;ib[i%lenb]) { printf(">\n"); flag=1; break; } } if(!flag) { printf("=\n"); } } return 0; } 后来得知的一个结论是,对于两个循环字符串字典序比较,s循环大于t循环,等价于st大于ts。这可真是有趣的结论,大概比这个暴力算法更优吧。 没错,把字符串的循环类比为26进制的无限循环小数,很nice的解法。 =====I===== 最难的一道题。网络流学得不好,唉。 #include #include char g[1049][1049],inque[1049],inpath[1049]; char inhua[1049]; int st,ed,newbase,ans,ne; int base[1049],pre[1049],match[1049]; int head,tail,que[1049]; int a[1049],b[1049],d[1049],mp[1049][1049],m,n; int lca(int u,int v) { memset(inpath,0,sizeof(inpath)); while(1) { u=base[u]; inpath[u]=1; if(u==st) { break; } u=pre[match[u]]; } while(1) { v=base[v]; if(inpath[v]) { break; } v=pre[match[v]]; } return v; } void reset(int u) { int v; while(base[u]!=newbase) { v=match[u]; inhua[base[u]]=inhua[base[v]]=1; u=pre[v]; if(base[u]!=newbase) { pre[u]=v; } } } void contract(int u,int v) { newbase=lca(u,v); memset(inhua,0,sizeof(inhua)); reset(u); reset(v); if(base[u]!=newbase) { pre[u]=v; } if(base[v]!=newbase) { pre[v]=u; } int i; for(i=1;i<=ne;i++) { if(inhua[base[i]]) { base[i]=newbase; if(!inque[i]) { que[tail]=i; tail++; inque[i]=1; } } } } void findaug() { memset(inque,0,sizeof(inque)); memset(pre,0,sizeof(pre)); int i; for(i=1;i<=ne;i++) { base[i]=i; } head=tail=1; que[tail]=st; tail++; inque[st]=1; ed=0; while(head0)&&pre[match[v]]>0) { contract(u,v); } else if(pre[v]==0) { pre[v]=u; if(match[v]>0) { que[tail]=match[v]; tail++; inque[match[v]]=1; } else { ed=v; return; } } } } } } void aug() { int u,v,w; u=ed; while(u>0) { v=pre[u]; w=match[v]; match[v]=u; match[u]=v; u=w; } } void edmonds() { memset(match,0,sizeof(match)); int u; for(u=1;u<=ne;u++) { if(match[u]==0) { st=u; findaug(); if(ed>0) { aug(); } } } } void create() { ne=0; memset(g,0,sizeof(g)); int i; for(i=1;i<=n;i++) { int j; for(j=1;j<=d[i];j++) { mp[i][j]=++ne; } } for(i=0;i =====J===== 我大概是快速幂爱好者,可能不太喜欢递归。这个题要交C++14而不是C++11才不会RE。 #include #define MOD 998244353 long long fact[4000010]; long long init() { fact[0]=1; long long i; for(i=1;i<4000005;i++) { fact[i]=(fact[i-1]*i)%MOD; } } long long QPow(long long bas,long long t) { long long ret=1; for(;t;t>>=1,bas=(bas*bas)%MOD) { if(t&1LL) { ret=(ret*bas)%MOD; } } return ret; } int n; int main() { init(); while(~scanf("%d",&n)) { long long a=(fact[n]*fact[n])%MOD; long long b=QPow(fact[2*n+1],(long long)998244351); printf("%lld\n",(a*b)%MOD); } } 贴一下标程的做法。 static inline int inv(int a) { return a == 1 ? 1 : MOD - 1LL * (MOD / a) * inv(MOD % a) % MOD; } //求数论倒数的函数并使用内联提高运行效率 =====A===== 从这里以下是补题的部分。 题目:定义字符串到字符串的映射F,第i位为字符串t第i位ti,到前面相同字符的距离,若没有则为0。 给出两元素a,b组成的长为n的串t,要回答其所有后缀作用F后字典序的排列。 标程定理:对于只有两元的串,这里的F和G等价。 G仅将“到前面相同字符的距离,若没有则为0”改为“到后面相同字符的距离,若没有则为n,并且在末端补充n+1”。 总之是神奇字符串结论。先记下来。 #include char str[100010]; int s[100010],sa[100010],rk[100010],t[100010],c[100010],height[100010]; void getsa(int n,int m) { s[n++]=0; int *x=rk,*y=t,i,k,num; for(i=0;i=0;i--) { --c[x[i]]; sa[c[x[i]]]=i; } for(k=1,num=1;num=k) { y[num]=sa[i]-k; num++; } } for(i=0;i=0;i--) { --c[x[y[i]]]; sa[c[x[y[i]]]]=y[i]; } int *temp=x; x=y; y=temp; x[sa[0]]=0; num=1; for(i=1;i=0;i--) { if(str[i]=='a') { s[i]=(a==n+1)?n:a-i; a=i; } else { s[i]=(b==n+1)?n:b-i; b=i; } } getsa(n+1,n+2); getheight(n+1); for(i=n;i;i--) { printf("%d ",1+sa[i]); } puts(""); } return 0; } =====H===== 快速读入与费用流。 每条边的费用已知,容量在每次询问时给出,每次询问求流出1单位的最小费用。 可以先假设每条边容量为1,每次给出具体容量时再做调整。 #include #include #include #include using namespace std; int read() { int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') { w=-1; } ch=getchar(); } while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); } return s*w; } long long gcd(long long a,long long b) { return b==0?a:gcd(b,a%b); } long long sum[2005]; int n,m,q,num; int head[2005],dis[2005],h[2005],PrePoint[2005],PreEdge[2005]; vector mcost; struct node { int u,v,f,w,nxt; }; struct node edge[2005]; void addedge(int x,int y,int f,int z) { edge[num].u=x; edge[num].v=y; edge[num].f=f; edge[num].w=z; edge[num].nxt=head[x]; head[x]=num++; } void add(int u,int v,int w,int c) { addedge(u,v,w,c); addedge(v,u,0,-c); } int MCMF(int s,int t) { int ansflow=0; int i; for(i=1;i<=n;i++) { h[i] = 0; } while(1) { priority_queue >q; for(i=1;i<=n;i++) { dis[i] = 1<<30; } dis[s]=0; q.push(make_pair(0,s)); while(q.size()!=0) { pair p=q.top(); q.pop(); if(-p.first!=dis[p.second]) { continue; } if(p.second==t) { break; } for(i=head[p.second];i!=-1;i=edge[i].nxt) { int nowcost=edge[i].w+h[p.second]-h[edge[i].v]; if(edge[i].f>0&&dis[edge[i].v]>dis[p.second]+nowcost) { dis[edge[i].v]=dis[p.second]+nowcost; q.push(make_pair(-dis[edge[i].v],edge[i].v)); PrePoint[edge[i].v]=p.second; PreEdge[edge[i].v]=i; } } } if(dis[t]==1<<30) { break; } for(i=1;i<=n;i++) { h[i]+=dis[i]; } int nowflow=1<<30; int now; for(now=t;now!=s;now=PrePoint[now]) { nowflow=min(nowflow,edge[PreEdge[now]].f); } for(now=t;now!=s;now=PrePoint[now]) { edge[PreEdge[now]].f-=nowflow; edge[PreEdge[now]^1].f+=nowflow; } ansflow+=nowflow; mcost.push_back(h[t]); } return ansflow; } int main() { long long u,v,c; while(~scanf("%d%d",&n,&m)) { int i; for(i=1;i<=n;i++) { head[i] = -1; } num = 2; mcost.clear(); int s = 1,t = n; for(i=1;i<=m;i++) { u = read(); v = read(); c = read(); add(u,v,1,c); } int maxflow = MCMF(s,t); sort(mcost.begin(),mcost.end()); int sz = mcost.size(); for(i=1;i<=sz;i++) { sum[i] = sum[i-1] + mcost[i-1]; } int q = read(); while(q--) { u = read(); v = read(); if(u*maxflow>1; if(u*mid >= v) { pos = mid; R=mid-1; } else { L = mid+1; } } long long a = u*sum[pos-1]; long long o = (v-u*(pos-1)) * (sum[pos] - sum[pos-1]); a = a+o; long long g = gcd(a,v); a /= g; v /= g; printf("%lld/%lld\n",a,v); } } } return 0; }