• test20190818


    闲扯

    哇,今天的考试好迷啊,题解都没有。。

    (T1) 没想到能多次向一个点派送士兵,然后就只过了最后连个用来 (hack) 的点???

    (T2) 一道神仙数学题,机房的 (dalao) 们讨论了两节课还没结果,现在还在改。。

    (T3) 我第一反应就是网络流,但是不知道怎么建图,结果是两颗 (Trie) 树,在节点连边,然后找最小割。。。之前嫌麻烦就没去学,有点后悔啊。。。

    题面

    题面

    (T1)

    Solution

    我们可以发现,对于每一个派送 (k) 个士兵的节点 (x) ,产生的价值为 (size_x imes k+sum dep_i) 。其中 (size) 为以 (1) 为根结点时,以 (x) 为根节点的子树的大小, (dep_i) 表示该子树中的节点 (i)(x) 的距离。

    需要注意的是,当一个点被派送了多次士兵时,不能简单地对 (k) 进行累加,事实上,新的贡献为 (size_xcdot sum k+mcdot sum dep_i)

    因为答案是和根结点有关的,考虑换根。

    先用 (DFS) 维护出此时每一个点的 (sum dep_i) 和子树大小 (size_x)

    然后对于每一次派送,增加的答案计入总数,同时统计对这个点一共派送了的次数也派送士兵的总数。

    然后再用一个 (DFS) 来进行换根操作。

    经过分析可以得知,每一次换根时,对答案有影响的点只会是当前根节点和即将转移到的点,当且仅当有向该点派送过士兵时成立。(因为其他点都已经在某颗子树中了,不会以它为子树的根节点产生新的贡献)不知道 解释清楚没,凑合着看吧

    转移时,我们先将新的根结点对当前根节点的贡献减掉,然后再加上换根之后新产生的贡献,统计答案。具体如下:

    新的根结点对当前根节点的贡献:( (cs) 表示 (rt) 这个点派送得次数, (ex) 表示 (sum dep_i)(add) 表示 (sum k)

    (val=cs_{rt}*(ex_{to}+size_{to})+add_{rt}*size_{to})

    同时因为换了新的根,所以 (sum dep_i) 可能会发生变化,也需要更新:

    (ex_{to}=ex_{rt}+n-2*size_{to})

    产生的新的贡献为:(其中 (exval) 表示以 (1) 为根时的 (ex)

    (cs_{to}*(ex_{rt}-exval_{to})+add_{to}*(n-size_{to}))

    然后,找到最小解和对应的所有节点,排序后输出即可。

    Code

    #include<bits/stdc++.h>
    #define del(a,i) memset(a,i,sizeof(a))
    #define ll long long
    #define inl inline
    #define il inl void
    #define it inl int
    #define ill inl ll
    #define re register
    #define ri re int
    #define rl re ll
    #define mid ((l+r)>>1)
    #define lowbit(x) (x&(-x))
    #define INF 0x3f3f3f3f
    using namespace std;
    template<class T>il read(T &x){
    	int f=1;char k=getchar();x=0;
    	for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
    	for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
    	x*=f;
    }
    template<class T>il print(T x){
    	if(x/10) print(x/10);
    	putchar(x%10+'0');
    }
    ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
    it qpow(int x,int m,int mod){
    	int res=1,bas=x%mod;
    	while(m){
    		if(m&1) res=(res*bas)%mod;
    		bas=(bas*bas)%mod,m>>=1;
    	}
    	return res%mod;
    }
    const int MAXN = 5e5+5;
    int n,m,u,v,x,k,head[MAXN],num_edge,cap[MAXN],num;
    struct Edge{
    	int next,to;
    	Edge(){}
    	Edge(int next,int to):next(next),to(to){}
    }edge[MAXN<<1];
    il add_edge(int u,int v){
    	edge[++num_edge]=Edge(head[u],v),head[u]=num_edge;
    	edge[++num_edge]=Edge(head[v],u),head[v]=num_edge;
    }
    int f[MAXN],sz[MAXN],add[MAXN],cs[MAXN];
    ll ex_val[MAXN],ans;
    bool tr[MAXN];
    il DFS(int u,int fa){
    	f[u]=fa,sz[u]=1;
    	for(ri i=head[u];i;i=edge[i].next){
    		if(edge[i].to==fa) continue;
    		DFS(edge[i].to,u);sz[u]+=sz[edge[i].to];
    		ex_val[u]+=ex_val[edge[i].to]+sz[edge[i].to];
    	}
    }
    il DFS1(int u,ll val,ll ex){
    	if(tr[u]) val+=1ll*cs[u]*(ex-ex_val[u])+1ll*add[u]*(n-sz[u]);
    	if(val==ans) cap[++num]=u;
    	else if(val<ans) ans=val,cap[num=1]=u;
    	for(ri i=head[u];i;i=edge[i].next){
    		if(edge[i].to==f[u]) continue;
    		rl tval=val-(tr[u]?1ll*cs[u]*(ex_val[edge[i].to]+sz[edge[i].to])+1ll*add[u]*sz[edge[i].to]:0);
    		rl tex=ex-2*sz[edge[i].to]+n;
    		DFS1(edge[i].to,tval,tex);
    	}
    }
    int main()
    {
    	freopen("A.in","r",stdin);
    	freopen("A.out","w",stdout);
    	read(n),read(m);
    	for(ri i=1;i<n;++i) read(u),read(v),add_edge(u,v);
    	DFS(1,0);
    	for(ri i=1;i<=m;++i) read(x),read(k),tr[x]=1,add[x]+=k,cs[x]++,ans+=1ll*k*sz[x]+ex_val[x];
    	cap[++num]=1;rl tmp=ans;
    	for(ri i=head[1];i;i=edge[i].next){
    		rl val=tmp-(tr[1]?1ll*cs[1]*(ex_val[edge[i].to]+sz[edge[i].to])+1ll*add[1]*sz[edge[i].to]:0);
    		rl ex=ex_val[1]+n-2*sz[edge[i].to];
    		DFS1(edge[i].to,val,ex);
    	}
    	printf("%lld
    ",ans);sort(cap+1,cap+1+num);
    	for(ri i=1;i<=num;++i) printf("%d ",cap[i]);
    	return 0;
    }
    

    (T2)

    Solution

    将每次变换看做一个矩阵,转化为矩阵的 (BSGS) .

    由于矩阵可能没有逆,所以最后再判一下解是否合法.

    时间复杂度 (O(Tcdot sqrt{P} cdot logsqrt{P}))

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
    	int out=0,fh=1;
    	char jp=getchar();
    	while ((jp>'9'||jp<'0')&&jp!='-')
    		jp=getchar();
    	if (jp=='-')
    		fh=-1,jp=getchar();
    	while (jp>='0'&&jp<='9')
    		out=out*10+jp-'0',jp=getchar();
    	return out*fh;
    }
    int k,b,x0,P;
    int add(int a,int b)
    {
    	return (a+b>=P)?(a+b-P):(a+b);
    }
    int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    typedef pair<int,int> pii;
    struct Matrix
    {
    	int v[2][2];
    	pii Hash()
    	{
    		return make_pair(v[0][0],v[1][0]);	
    	}
    	Matrix(){memset(v,0,sizeof v);}
    	Matrix operator * (const Matrix &rhs) const
    	{
    		Matrix res;
    		for(int k=0;k<2;++k)
    			for(int i=0;i<2;++i)
    				if(v[i][k])
    					for(int j=0;j<2;++j)
    						res.v[i][j]=add(res.v[i][j],mul(v[i][k],rhs.v[k][j]));
    		return res;	
    	}	
    	/*void pr()
    	{
    		for(int i=0;i<2;++i)
    		{
    			for(int j=0;j<2;++j)
    				printf("%d ",v[i][j]);
    			puts("");
    		}
    	}*/
    }I,trans,tmp,st;
    Matrix fpow(Matrix a,int b)
    {
    	Matrix res=I;
    	while(b)
    	{
    		if(b&1)
    			res=res*a;
    		a=a*a;
    		b>>=1;
    	}
    	return res;
    }
    int pk,pb,px,pp=-1,ls;
    map<pii,int> mp;
    int solve()
    {
    	k=read(),b=read(),x0=read(),P=read();
    	if(k==pk && b==pb && x0==px && P==pp)
    		return ls;
    	pk=k,pb=b,px=x0,pp=P;
    	if(k==0)
    	{
    		if(b!=x0)
    			return ls=-1;
    		else
    			return ls=1;
    	}	
    	trans.v[0][0]=k,trans.v[0][1]=trans.v[1][1]=1;
    	tmp.v[0][0]=x0,tmp.v[1][0]=b;
    	mp.clear();
    	int m=ceil(sqrt(P));
    	Matrix pw=I;
    	for(int j=0;j<m;++j)
    	{
    		st=pw*tmp;
    		mp[st.Hash()]=j;
    		pw=pw*trans;
    	}
    	Matrix tt=fpow(trans,m);
    	pw=tt;
    	for(int i=1;i*m-m+1<=P;++i)
    	{
    		st=pw*tmp;
    		pii val=st.Hash();
    		if(mp.find(val)!=mp.end())
    		{
    			int j=mp[val];
    			st=fpow(trans,i*m-j)*tmp;
    			if(st.v[0][0]==x0)
    				return ls=i*m-mp[val];
    			else
    				return ls=-1;
    		}	
    		pw=pw*tt;
    	}
    	return ls=-1;
    }
    int main()
    {
    	freopen("B.in","r",stdin);
    	freopen("B.out","w",stdout);
    	I.v[0][0]=I.v[1][1]=1;
    	int T=read();
    	while(T--)
    		printf("%d
    ",solve());
    	return 0;
    }
    

    ps

    以上内容均来自 (@jklover)

    (T3)

    Solution

    将每个数看做 (0/1) 串,正着建一棵字典树,反着建一棵字典树.

    那么每个前缀武器就能在前缀的字典树树上割下一颗子树,每个后缀武器能的后缀的字典树上割下一颗子树.

    每个给出的点在两棵树上至少被割掉一次,可以将两颗树拼在一起,建立一个最小割模型。

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <set>
    #include <vector>
    #include <string>
    #include <stack>
    #include <bitset>
    #define eps 1e-8
    #define FI first
    #define SE second
    using namespace std;
    typedef long long LL;
    
    const int MAXN = 20010;
    const int MAXM = 880010;
    const int INF = 0x3f3f3f3f;
    
    struct Node
    {
        int from,to,next;
        int cap;
    }edge[MAXM];
    int tol;
    int head[MAXN];
    int dep[MAXN];
    int gap[MAXN];
    
    int n;
    
    void init()
    {
        tol=0;
        memset(head,-1,sizeof(head));
    }
    
    void addedge(int u,int v,int w)
    {
        edge[tol].from=u;
        edge[tol].to=v;
        edge[tol].cap=w;
        edge[tol].next=head[u];
        head[u]=tol++;
        edge[tol].from=v;
        edge[tol].to=u;
        edge[tol].cap=0;
        edge[tol].next=head[v];
        head[v]=tol++;
    }
    void BFS(int start,int end)
    {
        memset(dep,-1,sizeof(dep));
        memset(gap,0,sizeof(gap));
        gap[0]=1;
        int que[MAXN];
        int front,rear;
        front=rear=0;
        dep[end]=0;
        que[rear++]=end;
        while(front!=rear)
        {
            int u=que[front++];
            if(front==MAXN)front=0;
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].to;
                if(dep[v]!=-1)continue;
                que[rear++]=v;
                if(rear==MAXN)rear=0;
                dep[v]=dep[u]+1;
                ++gap[dep[v]];
            }
        }
    }
    int SAP(int start,int end)
    {
        int res=0;
        BFS(start,end);
        int cur[MAXN];
        int S[MAXN];
        int top=0;
        memcpy(cur,head,sizeof(head));
        int u=start;
        int i;
        while(dep[start]<n)
        {
            if(u==end)
            {
                int temp=INF;
                int inser;
                for(i=0;i<top;i++)
                   if(temp>edge[S[i]].cap)
                   {
                       temp=edge[S[i]].cap;
                       inser=i;
                   }
                for(i=0;i<top;i++)
                {
                    edge[S[i]].cap-=temp;
                    edge[S[i]^1].cap+=temp;
                }
                res+=temp;
                top=inser;
                u=edge[S[top]].from;
            }
            if(u!=end&&gap[dep[u]-1]==0)
              break;
            for(i=cur[u];i!=-1;i=edge[i].next)
               if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)
                 break;
            if(i!=-1)
            {
                cur[u]=i;
                S[top++]=i;
                u=edge[i].to;
            }
            else
            {
                int min=n;
                for(i=head[u];i!=-1;i=edge[i].next)
                {
                    if(edge[i].cap==0)continue;
                    if(min>dep[edge[i].to])
                    {
                        min=dep[edge[i].to];
                        cur[u]=i;
                    }
                }
                --gap[dep[u]];
                dep[u]=min+1;
                ++gap[dep[u]];
                if(u!=start)u=edge[S[--top]].from;
            }
        }
        return res;
    }
    
    int ch[MAXN][2], w[MAXN], tot;
    inline int newnode() {
        int x = tot++;
        ch[x][0] = ch[x][1] = -1;
        w[x] = INF;
        return x;
    }
    
    int Insert(int p, int x) {
        for(int i = 7; i >= 0; --i) {
            int k = (x >> i) & 1;
            if(ch[p][k] == -1) ch[p][k] = newnode();
            p = ch[p][k];
        }
        return p;
    }
    
    void Find(int p, char *s, int v) {
        for(int i = 0; s[i]; ++i) {
            int k = s[i] - '0';
            if(ch[p][k] == -1) return;
            p = ch[p][k];
        }
        w[p] = min(w[p], v);
    }
    
    inline int rev(int x) {
        int t = 0;
        for(int i = 0; i < 8; ++i) if(x & (1 << i)) {
            t |= 1 << (7 - i);
        }
        return t;
    }
    
    void dfs1(int u) {
        for(int i = 0; i < 2; ++i) {
            if(ch[u][i] == -1) continue;
            addedge(u, ch[u][i], w[ch[u][i]]);
            dfs1(ch[u][i]);
        }
    }
    
    void dfs2(int u) {
        for(int i = 0; i < 2; ++i) {
            if(ch[u][i] == -1) continue;
            addedge(ch[u][i], u, w[ch[u][i]]);
            dfs2(ch[u][i]);
        }
    }
    
    char s[MAXN];
    int id1[500], id2[500];
    
    int main() {
        freopen("C.in", "r", stdin);
        freopen("C.out", "w", stdout);
        int N, M;
        scanf("%d%d", &N, &M);
        tot = 0;
        int rt1 = newnode(), rt2 = newnode();
        for(int x, i = 0; i < N; ++i) {
            scanf("%d", &x);
            id1[i] = Insert(rt1, x);
            id2[i] = Insert(rt2, rev(x));
        }
        for(int i = 0; i < M; ++i) {
            char op[2]; int w;
            scanf("%s%s%d", op, s, &w);
            if(strlen(s) > 8) continue;
            if(*op == 'P') {
                Find(rt1, s, w);
            }
            else {
                reverse(s, s + strlen(s));
                Find(rt2, s, w);
            }
        }
        init();
        for(int i = 0; i < N; ++i) {
            addedge(id1[i], id2[i], INF);
        }
        dfs1(rt1); dfs2(rt2);
        n = tot + 2;
        int ans = SAP(rt1, rt2);
        if(ans >= INF) ans = -1;
        printf("%d
    ", ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    

    ps

    以上题解来自 (@jklover) ,程序来自某不知名的 (std)

    总结

    蒟蒻无语了。。。。

  • 相关阅读:
    11-15SQLserver基础--数据库之范式理论
    11-13SQLserver基础--数据库之事务
    11-11SQLserver基础--数据库之触发器
    C#中abstract和virtual区别
    virtual修饰符
    override 修饰符
    访问public
    访问修饰符protected
    访问修饰符private
    访问修饰符internal
  • 原文地址:https://www.cnblogs.com/TheShadow/p/11375654.html
Copyright © 2020-2023  润新知