======牛客多校第一场======
因为事务繁忙、时间紧迫,这里的题解区仅暂存一下通关代码。
有趣的是,过的几个题都是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;
}