时间不多了,然而hdu的多校还没开始补。。博主打算先解决掉>=100人的题,其他的题等以后再补吧。
Problem E. TeaTree
第一次见线段树合并的题,没想到线段树还能这么用。真好玩。。
这题没什么逻辑问题,std也写的很好。这里就不多说了。
#include
using namespace std;
const int maxv=1e5+5;
const int maxn=1e5+5;
const int maxnd=8.1e7+10;
vector<int>V[maxv];
void init()
{
for(int i=1;ifor(int j=1;j*iint root[maxn];
int tot;
int ch[maxnd][2];
int newnode()
{
tot++;
ch[tot][0]=ch[tot][1]=0;
return tot;
}
void build(int l,int r,int v,int &rt)
{
if(rt==0)rt=newnode();
if(l==r)return;
int m=l+r>>1;
if(v<=m)build(l,m,v,ch[rt][0]);
else build(m+1,r,v,ch[rt][1]);
}
int f;
int ans[maxn];
int fa[maxn];
int merge(int root1,int root2,int l,int r)
{
if(root1==0||root2==0)
{
return root1^root2;
}
if(l==r)
{
ans[f]=max(ans[f],l);
return root1;
}
int m=l+r>>1;
ch[root1][0]=merge(ch[root1][0],ch[root2][0],l,m);
ch[root1][1]=merge(ch[root1][1],ch[root2][1],m+1,r);
return root1;
}
int main()
{
init();
memset(ans,-1,sizeof(ans));
int n;
scanf("%d",&n);
for(int i=2;i<=n;i++)
scanf("%d",&fa[i]);
int x;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
root[i]=newnode();
for(int j=0;j1,maxv,V[x][j],root[i]);
}
for(int i=n;i>=1;i--)
{
f=fa[i];
root[f]=merge(root[f],root[i],1,maxv);
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}
Problem G. Cyclic
比赛的时候oeis过的,我觉得这样不行。。
看了题解才觉得自己推公式才最爽。题解也写的很详细了。
#include
using namespace std;
const int mod=998244353;
const int maxn=1e5+5;
//***************************************************
//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
long long extgcd(long long a,long long b,long long &x,long long &y)
{
if(a==0&&b==0)return -1;//无最大公约数
if(b==0){x=1;y=0;return a;}
long long d=extgcd(b,a%b,y,x);
y-=a/b*x;
return d;//返回gcd(a,b)
}
//****************求逆元******************************
//ax=1(mod n)
long long mod_reverse(long long a,long long n)
{
long long x,y;
long long d=extgcd(a,n,x,y);
if(d==1)return (x%n+n)%n;
return -1;
}
long long tab1[maxn],tab2[maxn];
void init()
{
tab1[0]=1;
for(int i=1;i<=100000;i++)
tab1[i]=tab1[i-1]*i%mod;
tab2[100000]=mod_reverse(tab1[100000],mod);
for(int i=99999;i>=0;i--)
tab2[i]=tab2[i+1]*(i+1)%mod;
}
long long C(int a,int b)
{
return tab1[a]*tab2[b]%mod*tab2[a-b]%mod;
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
long long ans=0;
for(int i=0;iint flag=(i%2?-1:1);
ans=(ans+1LL*flag*C(n,i)*tab1[n-1-i]%mod)%mod;
}
if(n%2)ans--;
else ans++;
printf("%lld\n",(ans%mod+mod)%mod);
}
}
Problem I. Count
这个题也是oeis过的呜呜呜。。
题解已经将式子化成这样
∑ni=1∑i−1a=1[gcd(2i−a,a)=1] ∑ i = 1 n ∑ a = 1 i − 1 [ g c d ( 2 i − a , a ) = 1 ]
为什么会往下面化呢,这里说明两点内容。
1,x如果与n互质->n-x与n互质
2,n是奇数->与n互质的奇数占一半
#include
using namespace std;
const int maxn=2e7+5;
int phi[maxn];
void phi_table(int n)
{
for(int i=2;i<=n;i++)phi[i]=0;
phi[1]=1;
for(int i=2;i<=n;i++)if(!phi[i])
for(int j=i;j<=n;j+=i)
{
if(!phi[j])phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
long long sum[maxn];
void init()
{
phi_table(maxn-5);
for(int i=2;i<=maxn-5;i++)
{
sum[i]=sum[i-1];
if(i%2)
sum[i]+=phi[i]/2;
else sum[i]+=phi[i];
}
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
printf("%lld\n",sum[n]);
}
return 0;
}
Problem J. CSGO
这题好巧妙啊。。
由于k不大,后面的累加实际上可以用(1<
#include
using namespace std;
long long S[1<<5],B[1<<5];
const long long inf=0x3f3f3f3f3f;
int x[6];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(S,-inf,sizeof(S));
memset(B,-inf,sizeof(B));
int n,m,K;
scanf("%d %d %d",&n,&m,&K);
for(int i=1;i<=n;i++)
{
int val;
scanf("%d",&val);
for(int j=0;jscanf("%d",&x[j]);
for(int j=0;j<(1<long long res=0;
for(int k=0;k>k)&1)<<1)-1)*x[k];
res+=val;
S[j]=max(S[j],res);
}
}
for(int i=1;i<=m;i++)
{
int val;
scanf("%d",&val);
for(int j=0;jscanf("%d",&x[j]);
for(int j=0;j<(1<long long res=0;
for(int k=0;k>k)&1)<<1)-1)*x[k];
res+=val;
B[j]=max(B[j],res);
}
}
long long ans=-inf;
for(int i=0;i<(1<1<1-i]);
printf("%lld\n",ans);
}
return 0;
}
Problem L.Videos
这个费用流建图方式也好棒啊。。
题解讲的很详细了。
#include
using namespace std;
const int maxn1=205;
//下标从0到N-1
//最小费用最大流,求最大费用只需取相反数,结果取相反数即可。
const int maxn=800;
const int maxm=maxn*maxn;
const int inf=0x3f3f3f3f;
struct Edge
{
int to,next,cap,flow,cost;
Edge(int _t,int _n,int _c,int _f,int _cost):to(_t),next(_n),cap(_c),flow(_f),cost(_cost){}
Edge(){}
}edges[maxm];
int head[maxn],tot;
int pre[maxn],dis[maxn];
bool vis[maxn];
int N;
void init(int n)
{
N=n;
tot=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int cap,int cost)
{
edges[tot]=Edge(v,head[u],cap,0,cost);
head[u]=tot++;
edges[tot]=Edge(u,head[v],0,0,-cost);
head[v]=tot++;
}
bool spfa(int s,int t)
{
queue<int>q;
for(int i=0;ifalse;
pre[i]=-1;
}
dis[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=false;
for(int i=head[u];~i;i=edges[i].next)
{
int v=edges[i].to;
if(edges[i].cap>edges[i].flow&&dis[v]>dis[u]+edges[i].cost)
{
dis[v]=dis[u]+edges[i].cost;
pre[v]=i;
if(!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
if(pre[t]==-1)return 0;
return 1;
}
int minCostMaxflow(int s,int t,int &cost)
{
int flow=0;
cost=0;
while(spfa(s,t))
{
int Min=inf;
for(int i=pre[t];~i;i=pre[edges[i^1].to])
{
if(Min>edges[i].cap-edges[i].flow)
Min=edges[i].cap-edges[i].flow;
}
for(int i=pre[t];~i;i=pre[edges[i^1].to])
{
edges[i].flow+=Min;
edges[i^1].flow-=Min;
cost+=edges[i].cost*Min;
}
flow+=Min;
}
return flow;
}
int id[maxn1][2];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m,k,W;
scanf("%d %d %d %d",&n,&m,&k,&W);
int tot1=0;
int S=++tot1,T=++tot1;
id[0][0]=id[0][1]=++tot1;
for(int i=1;i<=n;i++)
{
id[i][0]=++tot1;
id[i][1]=++tot1;
}
init(maxn);
addedge(S,id[0][0],k,0);
id[n+1][0]=id[n+1][1]=T;
for(int i=0;i<=n;i++)
{
addedge(id[i][0],id[i+1][0],inf,0);
addedge(id[i][1],id[i+1][1],inf,0);
}
int st,ed,w,op;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d %d",&st,&ed,&w,&op);
++tot1;
addedge(id[st][op],tot1,1,0);
addedge(tot1,id[ed][!op],1,-w);
addedge(tot1,id[ed][op],1,W-w);
}
int ct;
minCostMaxflow(S,T,ct);
printf("%d\n",-ct);
}
return 0;
}