ACM-ICPC 2018 徐州赛区网络预赛(除C、E外题解)

4 篇文章 0 订阅

ACM-ICPC 2018 Xuzhou Online 徐州赛区网络赛(除C、E外题解)


A Hard to prepare (递推规律)

题目链接
题面:

(骗搜索)
After Incident, a feast is usually held in Hakurei Shrine. This time Reimu asked Kokoro to deliver a Nogaku show during the feast. To enjoy the show, every audience has to wear a Nogaku mask, and seat around as a circle.

There are N guests Reimu serves. Kokoro has 2^k2
k
masks numbered from 0,1,\cdots,0,1,⋯, 2^k - 12
k
−1, and every guest wears one of the masks. The masks have dark power of Dark Nogaku, and to prevent guests from being hurt by the power, two guests seating aside must ensure that if their masks are numbered ii and jj , then ii XNOR jj must be positive. (two guests can wear the same mask). XNOR means ~(ii^jj) and every number has kk bits. (11 XNOR 1 = 11=1, 00 XNOR 0 = 10=1, 11 XNOR 0 = 00=0)

You may have seen 《A Summer Day’s dream》, a doujin Animation of Touhou Project. Things go like the anime, Suika activated her ability, and the feast will loop for infinite times. This really troubles Reimu: to not make her customers feel bored, she must prepare enough numbers of different Nogaku scenes. Reimu find that each time the same guest will seat on the same seat, and She just have to prepare a new scene for a specific mask distribution. Two distribution plans are considered different, if any guest wears different masks.

In order to save faiths for Shrine, Reimu have to calculate that to make guests not bored, how many different Nogaku scenes does Reimu and Kokoro have to prepare. Due to the number may be too large, Reimu only want to get the answer modules 1e9+71e9+7 . Reimu did never attend Terakoya, so she doesn’t know how to calculate in module. So Reimu wishes you to help her figure out the answer, and she promises that after you succeed she will give you a balloon as a gift.

Input
First line one number TT , the number of testcases; (T \le 20)(T≤20) .

Next TT lines each contains two numbers, NN and k(0

题意:

给定N,K,要求一个串的总可能情况,这个串长度为N,首尾相接,每个位置可以填入 [0,2k1] [ 0 , 2 k − 1 ] ,使得相邻数不同时为a和~a。

思路:

只考虑第i个数对第(i+1)个数的影响:
1)当第(n-1)个数与第1个数不相同的时候,贡献为 2k(2k1)(n2)(2k2) 2 k ∗ ( 2 k − 1 ) ( n − 2 ) ∗ ( 2 k − 2 )
2)相同的时候,贡献为 ans[n2][k] a n s [ n − 2 ] [ k ] ,对应情况下的第n个数也随之多了有且仅有一种选择,相当于问题中的n减少了2;
递归累加两种情况即可。

AC代码:
const int MAXN = 1000005;
const ll MOD = 1e9+7 ;
const ll INF = 1e16+7;

int _;

using namespace std;

ll po2[MAXN];

void init()
{
    po2[0] = 1LL;
    for(int i=1;i<MAXN;++i)
        po2[i] = po2[i-1]*2LL%MOD;

}

ll powermod(ll n,ll k, ll MOD)
{
    ll ans=1;
    while(k)
    {
        if(k&1)
        {
            ans=((ans%MOD)*(n%MOD))%MOD;
        }
        n=((n%MOD)*(n%MOD))%MOD;
        k>>=1;
    }
    return ans;
}

ll solve(ll N, ll K)
{
    ll res = 0;
    if(N==1)    return po2[K];
    if(N==2)    return po2[K]*(po2[K]-1LL)%MOD;
    res = (po2[K]*powermod(po2[K]-1LL,N-2,MOD)%MOD*max(po2[K]-2LL,0LL)%MOD+solve(N-2,K))%MOD;
    return res;
}

int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.in","w+",stdout);
    init();
    ll N, K;
    TCASE(_)
    {
        scanf("%lld%lld",&N,&K);
        printf("%lld\n",solve(N,K));
    }
    return 0;
}

B BE,GE or NE (DP)

题目链接
题面:

(骗搜索)
262144K
In a world where ordinary people cannot reach, a boy named “Koutarou” and a girl named “Sena” are playing a video game. The game system of this video game is quite unique: in the process of playing this game, you need to constantly face the choice, each time you choose the game will provide 1-31−3 options, the player can only choose one of them. Each option has an effect on a “score” parameter in the game. Some options will increase the score, some options will reduce the score, and some options will change the score to a value multiplied by -1−1 .

That is, if there are three options in a selection, the score will be increased by 11, decreased by 11, or multiplied by -1−1. The score before the selection is 88. Then selecting option 11 will make the score become 99, and selecting option 22 will make the score 77 and select option 33 to make the score -8−8. Note that the score has an upper limit of 100100 and a lower limit of -100−100. If the score is 9999 at this time, an option that makes the score +2+2 is selected. After that, the score will change to 100100 and vice versa .

After all the choices have been made, the score will affect the ending of the game. If the score is greater than or equal to a certain value kk, it will enter a good ending; if it is less than or equal to a certain value ll, it will enter the bad ending; if both conditions are not satisfied, it will enter the normal ending. Now, Koutarou and Sena want to play the good endings and the bad endings respectively. They refused to give up each other and finally decided to use the “one person to make a choice” way to play the game, Koutarou first choose. Now assume that they all know the initial score, the impact of each option, and the kk, ll values, and decide to choose in the way that works best for them. (That is, they will try their best to play the ending they want. If it’s impossible, they would rather normal ending than the ending their rival wants.)

Koutarou and Sena are playing very happy, but I believe you have seen through the final ending. Now give you the initial score, the kk value, the ll value, and the effect of each option on the score. Can you answer the final ending of the game?

Input
The first line contains four integers n,m,k,ln,m,k,l(1\le n \le 10001≤n≤1000, -100 \le m \le 100−100≤m≤100 , -100 \le l < k \le 100−100≤l

题意:

两人玩同一个游戏,给定一个初始分数m,在n步后,若n不小于l则进入HE,不大于k则进入BE,否则进入NE。每一步每个人都有最多三种选择,+a,-b或*-1。第一个选择的人会尽可能让游戏进入HE,第二个则尽可能让游戏进入BE。

思路:

DP记忆化搜索。
对于上一步分数为t时,第一个人会选择让其尽可能大,第二个人会选择让其尽可能小,所以对应的选择后的分数情况也能求解。
最后看一下初始分数为m时的游戏结局即可。

AC代码:
const int MAXN = 50005;
const ll MOD = 2333333 ;
const ll INF = 1e16+7;

int _;

using namespace std;

int dp[1005][205];
int N;
int ch[1005][3];
int M, K, L;

int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.in","w+",stdout);
    while(scanf("%d%d%d%d",&N,&M,&K,&L)!=EOF)
    {
        REP(i,1,N)  scanf("%d%d%d",&ch[i][0],&ch[i][1],&ch[i][2]);
        memset(dp,0,sizeof(dp));
        K+=100, L+=100, M+=100;
        REP(i,0,200)
        {
            if(i<=L)    dp[N+1][i] = -1;
            else if(i>=K)   dp[N+1][i] = 1;
        }
        IREP(i,1,N)
        {
            REP(j,0,200)
                if(i&1)
                {
                    int&test = dp[i][j];
                    dp[i][j] = -1;
                    if(ch[i][0])    dp[i][j] = max(dp[i][j],dp[i+1][min(200,j+ch[i][0])]);
                    if(ch[i][1])    dp[i][j] = max(dp[i][j],dp[i+1][max(0,j-ch[i][1])]);
                    if(ch[i][2])    dp[i][j] = max(dp[i][j],dp[i+1][(100-j)+100]);

                }
                else
                {
                    dp[i][j] = 1;
                    if(ch[i][0])    dp[i][j] = min(dp[i][j],dp[i+1][min(200,j+ch[i][0])]);
                    if(ch[i][1])    dp[i][j] = min(dp[i][j],dp[i+1][max(0,j-ch[i][1])]);
                    if(ch[i][2])    dp[i][j] = min(dp[i][j],dp[i+1][(100-j)+100]);
                }
        }

        if(dp[1][M]==1)    printf("Good Ending\n");
        else if(dp[1][M]==-1)   printf("Bad Ending\n");
        else    printf("Normal Ending\n");
    }
    return 0;
}

D Easy Math (莫比乌斯反演+杜教筛)

题目链接
题面:

(骗搜索)
Given a positive integers n n , Mobius function μ(n) is defined as follows:

μ(n)=1(1)k0n=1n=p1p2pkother μ ( n ) = { 1 n = 1 ( − 1 ) k n = p 1 p 2 ⋯ p k 0 o t h e r
Given two integers mm, nn, please calculate mi=1μ(in)i=1mμ(in). ∑ i = 1 m μ ( i n ) ∑ i = 1 m ​ μ ( i n ) .
Input
One line includes two integers m (1 \le m \le 2e9)m(1≤m≤2e9), n (1 \le n \le 1e12)n(1≤n≤1e12) .

Output
One line includes the answer .

样例输入 复制
2 2
样例输出 复制
-1
题目来源
ACM-ICPC 2018 徐州赛区网络预赛

题意:

计算 Σmi=1μ(in) Σ i = 1 m μ ( i n )

思路:

莫比乌斯反演+筛法。

f(m,n)=Σmi=1μ(in)=Σmi=1μ(i)[gcd(i,n)=1]μ(n) f ( m , n ) = Σ i = 1 m μ ( i n ) = Σ i = 1 m μ ( i ) [ g c d ( i , n ) = 1 ] μ ( n )

代入莫比乌斯函数,得
f(m,n)=μ(n)Σmi=1μ(i)Σd|gcd(i,n)μ(d) f ( m , n ) = μ ( n ) Σ i = 1 m μ ( i ) Σ d | g c d ( i , n ) μ ( d )

变换一下,有
f(m,n)=μ(n)Σd|nμ(d)Σmd|iμ(i)=μ(n)Σd|nμ(d)f(m/d,d) f ( m , n ) = μ ( n ) Σ d | n μ ( d ) Σ d | i m μ ( i ) = μ ( n ) Σ d | n μ ( d ) ∗ f ( m / d , d )

枚举n的所有因子,用筛法求 f(m,n) f ( m , n )
事实上,
m=1f(m,n)=μ(n) m = 1 时 , f ( m , n ) = μ ( n )
n=1f(m,n)=Σni=1(i) n = 1 时 , f ( m , n ) = Σ i = 1 n ( i )
所以再用杜教筛处理一下前缀和就好了,复杂度不会算(tao

AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define ld long double
#define pb push_back
#define mp make_pair
#define X  first
#define Y  second
#define REP(i,st,ed)    for(int i=st;i<=ed;++i)
#define IREP(i,st,ed)   for(int i=ed;i>=st;--i)
#define TCASE(T)    cin>>T;while(T--)


const int MAXN = 2000005;
const ll MOD = 2333333 ;
const int INF = 1e9+7;

int _;

using namespace std;

ll N, M;

int rua(ll n)
{
    int cnt = 0;
    for(ll i = 2; i * i <= n; ++i)
    {
        if(n%i == 0)
        {
            n /= i;
            ++cnt;
            if(n%i == 0) return 0;
        }
    }
    if(n > 1) ++cnt;
    return cnt&1?-1:1;
}


bool check[MAXN];
int prime[MAXN];
int mu[MAXN];
int summ[MAXN];

void Moblus()
{
    memset(check,0,sizeof(check));
    mu[1] = 1;
    int tot = 0;
    for(int i=2; i<MAXN; ++i)
    {
        if(!check[i])
        {
            prime[++tot] = i;
            mu[i] = -1;
        }

        for(int j=1; j<=tot; ++j)
        {
            if(i*prime[j]>MAXN) break;
            check[i*prime[j]] = 1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]] = 0;
                break;
            }
            else    mu[i*prime[j]] = -mu[i];
        }
    }
    summ[0] = 0;
    for(int i=1; i<MAXN; ++i) summ[i] = summ[i-1]+mu[i];
}

ll get_mu(ll num)
{
    if(num<MAXN)    return 1LL*mu[num];
    else    return 1LL*rua(num);
}


struct p_my_map{
    ll x;
    int ans,next;
}p_e[MAXN+5];

int p_ans=0,p_num=0;
int p_head[MOD+5];

void p_ins(ll x,int sum)
{
    int j=x%MOD;
    p_e[++p_num]=(p_my_map){x,sum,p_head[j]};
    p_head[j]=p_num;
}

int p_calc(ll n)
{
    if(n<MAXN) return summ[n];
    for(int i=p_head[n%MOD];i;i=p_e[i].next)
        if(p_e[i].x==n)return p_e[i].ans;
    int sum=1,q=sqrt(n);
    for(int i=2;i<=q;i++)
        sum-=p_calc(n/i);
    q=n/(q+1);
    for(int i=1;i<=q;i++)
        sum-=(n/i-(n/(i+1)))*p_calc(i);
    p_ins(n,sum);
    return sum;
}


struct my_map
{
    ll x, y;
    int ans;
    int next;
} e[MAXN+5];

int ans=0,num=0;
int head[MOD+5];

void ins(ll x,ll y,int sum)
{
    int j=(x+y)%MOD;
    e[++num]=(my_map)
    {
        x,sum,head[j]
    };
    head[j]=num;
}

ll calc(ll n, ll m)
{
    if(m==0)    return 0;
    if(m==1)    return get_mu(n);
    if(n==1)    return p_calc(m);
    int tmp = get_mu(n);
    if(!tmp)    return 0;

    for(int i=head[(n+m)%MOD]; i; i=e[i].next)
        if(e[i].x==n&&e[i].y==m)   return e[i].ans;

    ll sum=0;
    for(ll i=1;i*i<=n;++i)
    {
        if(!(i==1||n%i==0)) continue;
        sum += get_mu(i)*calc(i,m/i);
        if(n/i!=i)  sum += get_mu(n/i)*calc(n/i,m/(n/i));
    }
    sum*=tmp;
    ins(n,m,sum);
    return sum;
}

int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.in","w+",stdout);
    Moblus();
    scanf("%lld%lld",&M,&N);

        int nnn = rua(N);
        if(nnn==0)  printf("%d\n",0);
        else
        {
            num = p_num = 0;
            printf("%lld\n",calc(N,M));
        }

}

F(STL::map)

题目链接
题意:

N帧,每帧都有k个特征点,求最长特征点连续出现帧数。

思路:

签到题,用STL map跑一跑就好了

AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define ld long double
#define pb push_back
#define mp make_pair
#define X  first
#define Y  second
#define REP(i,st,ed)    for(int i=st;i<=ed;++i)
#define IREP(i,st,ed)   for(int i=ed;i>=st;--i)
#define TCASE(T)    cin>>T;while(T--)


const int MAXN = 100005;
const ll MOD = 2333333 ;
const ll INF = 1e16+7;

int _;

using namespace std;

map< pair<int,int>, vector<int> > mapp;
vector<int> tmp;

int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.in","w+",stdout);
    TCASE(_)
    {
        mapp.clear();
        int N; scanf("%d",&N);
        REP(i,1,N)
        {
            int tp; scanf("%d",&tp);
            int x, y;
            REP(j,1,tp)
            {
                scanf("%d%d",&x,&y);
                mapp[mp(x,y)].pb(i);
            }
        }
        int ans = 0;
        map< pair<int,int>, vector<int> >::iterator it = mapp.begin();
        for(;it!=mapp.end();++it)
        {
            /*pair<int,int> test = it->X;
            cout<<test.X<<" "<<test.Y<<": ";
            for(int i:it->Y)
                cout<<i<<" ";
            cout<<endl;*/
            tmp = it->Y;
            int last = -1;
            int cnt = 0;
            for(int i=0;i<tmp.size();++i)
            {
                if(last==-1||last==tmp[i]-1)
                {
                    cnt++;
                    last = tmp[i];
                }
                else if(last!=tmp[i])
                {
                    ans = max(ans,cnt);
                    cnt = 1;
                    last = tmp[i];
                }
            }
            ans = max(ans,cnt);
        }
        printf("%d\n",ans);
    }
    return 0;
}

H Ryuji doesn’t want to study(树状数组BIT)

题目链接
题意:

给定一个长为N的数组,Q个询问,每次询问区间 [l,r] [ l , r ] ,求

a[l]L+a[l+1](L1)+...+a[r1]2+a[r]1 a [ l ] ∗ L + a [ l + 1 ] ∗ ( L − 1 ) + . . . + a [ r − 1 ] ∗ 2 + a [ r ] ∗ 1

思路:

用两个树状数组,一个记录前缀和,另一个记录 (Ni+1)a[i] ( N − i + 1 ) ∗ a [ i ] ,每次询问用后者减去 (NL) ( N − L ) 倍的前缀和即可。

AC代码:
const int MAXN = 100005;
const ll MOD = 2333333 ;
const ll INF = 1e16+7;

int _;

using namespace std;


ll BIT_1[MAXN];
ll BIT_2[MAXN];
ll num[MAXN];
ll N;

int lowbit(int x) { return x&-x; }

void update(ll* tree, int pos, ll val)
{
    while(pos < N)
    {
        tree[pos] += val;
        pos += lowbit(pos);
    }
}

ll query(ll* tree, int pos)
{
    ll res = 0;
    while(pos)
    {
        res += tree[pos];
        pos -= lowbit(pos);
    }
    return res;
}

int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.in","w+",stdout);
    int Q;
    while(scanf("%lld%lld",&N,&Q)!=EOF)
    {
        memset(BIT_1,0,sizeof(BIT_1));
        memset(BIT_2,0,sizeof(BIT_2));
        ll tmp;
        for(int i=1;i<=N;++i)
        {
            scanf("%lld",&tmp);
            num[i] = tmp;
            update(BIT_1,i,tmp);
            update(BIT_2,i,1LL*(N-i+1)*tmp);
        }
        ll op, x, y;
        while(Q--)
        {
            scanf("%lld%lld%lld",&op,&x,&y);
            if(op==1)
            {
                ll ans = (query(BIT_2,y)-query(BIT_2,x-1LL));
                ans -= 1LL*(N-x+1-(y-x+1))*(query(BIT_1,y)-query(BIT_1,x-1LL));
                printf("%lld\n",ans);
            }
            else
            {
                y = y-(query(BIT_1,x)-query(BIT_1,x-1));
                update(BIT_1,x,y);
                update(BIT_2,x,1LL*(N-x+1)*y);
            }
        }
    }
    return 0;
}

I Characters with Hash

题目链接
题意:

签到

思路:

签到

AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define ld long double
#define pb push_back
#define mp make_pair
#define X  first
#define Y  second
#define REP(i,st,ed)    for(int i=st;i<=ed;++i)
#define IREP(i,st,ed)   for(int i=ed;i>=st;--i)
#define TCASE(T)    cin>>T;while(T--)


const int MAXN = 1000005;
const ll MOD = 2333333 ;
const ll INF = 1e16+7;

int _;

using namespace std;

char ss[MAXN];
int N;
int L;

int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.in","w+",stdout);
    TCASE(_)
    {
        scanf("%d %c",&N,&L);
        scanf("%s",ss);
        int ans = 2*N;
        int flag = 0;
        for(int i=0;i<N;++i)
        {
            int tmp  = abs(L-(int)ss[i]);
            if(tmp==0)   ans -= 2;
            else 
            {
                if(tmp<10)   ans -= 1;
                break;
            }
            //cout<<tmp<<" ";
        }
        //cout<<endl;
        if(ans==0)  ans = 1;
        printf("%d\n",ans);
    }
    return 0;
}

J Maze Designer (最大生成树+LCA)

题目链接
题面:

(骗搜索)
After the long vacation, the maze designer master has to do his job. A tour company gives him a map which is a rectangle. The map consists of N \times MN×M little squares. That is to say, the height of the rectangle is NN and the width of the rectangle is MM. The master knows exactly how the maze is going to use. The tour company will put a couple in two different squares in the maze and make them seek each other. Of course,the master will not make them find each other easily. The only thing the master does is building some wall between some little squares. He knows in that way, wherever the couple is put, there is only one path between them. It is not a difficult thing for him, but he is a considerate man. He also knows that the cost of building every wall between two adjacent squares is different(Nobody knows the reason). As a result, he designs the maze to make the tour company spend the least money to build it.

Now, here’s your part. The tour company knows you’re the apprentice of the master, so they give you a task. you’re given QQ qustions which contain the information of where the couple will be put. You need to figure out the length of the shortest path between them.

However,the master doesn’t tell you how he designs the maze, but he believes that you, the best student of himself, know the way. So he goes on vacation again.

样例输入 复制
3 3
D 1 R 9
D 7 R 8
D 4 X 0
D 2 R 6
D 12 R 5
D 3 X 0
X 0 R 10
X 0 R 11
X 0 X 0
3
1 1 3 3
1 2 3 2
2 2 3 1
样例输出 复制
4
2
2

题意:

给一个N*M的矩形方格,在合法范围内的格子边上造墙,使得任意两点间有且只有一条路。在花费最小的情况下给Q个询问,询问两点间最短距离。

思路:

任意两点仅有一条路,显然最后的结果是一棵树。要使得花费最小,显然需要留下(选出)花费最大的边构造最大生成树。最后用LCA处理一下任意两点间最短路即可。

AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define ld long double
#define pb push_back
#define mp make_pair
#define X  first
#define Y  second
#define REP(i,st,ed)    for(int i=st;i<=ed;++i)
#define IREP(i,st,ed)   for(int i=ed;i>=st;--i)
#define TCASE(T)    cin>>T;while(T--)


const int MAXN = 300005;
const ll MOD = 2333333 ;
const ll INF = 1e16+7;

int _;

using namespace std;

int father[MAXN];
int N, M;

void init( )
{
    int i;
    for(i=1;i<=N*M;i++)
        father[i]=i;
}

int find(int x)
{
    while(father[x]!=x)
        x=father[x];
    return x;
}

void merge(int a,int b)
{
    int temp_a,temp_b;
    temp_a=find(a);
    temp_b=find(b);
    if(temp_a<temp_b)   swap(temp_a,temp_b);
    if(temp_a!=temp_b)
        father[temp_a]=temp_b;
}

struct edge
{
    int u,v;
    ll cost;
    int next;
    edge(int a=0,int b=0, int next=-1):u(a), v(b),next(next) {}
}edges[MAXN<<2];

int head[MAXN];
int curedgeno;

void mapp_init()
{
    memset(head,-1,sizeof(head));
    curedgeno = 0;
}

void add_edge(int u, int v, ll c)
{
    ++curedgeno;
    edges[curedgeno] = edge(u,v);
    edges[curedgeno].cost = c;
    edges[curedgeno].next = head[u];
    head[u] = curedgeno;
}

bool operator<(const edge& a, const edge& b)
{
    return a.cost < b.cost;
}

void kruskal()
{
    sort(edges+1,edges+1+curedgeno);
    init();
    edge temp;
    int cnt = 0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=curedgeno;++i)
    {
        temp = edges[i];
        if(find(temp.u)!=find(temp.v))
        {
            merge(temp.u,temp.v);
            add_edge(temp.u,temp.v,1);
            add_edge(temp.v,temp.u,1);
            cnt++;
        }
        if(cnt==N*M-1)  break;
    }
}

const int DEG = 30;

bool flag[MAXN];
int dis[MAXN];
queue<int> togo;

int fa[MAXN][DEG];
int deg[MAXN];

void BFS(int root)
{
    while(!togo.empty())    togo.pop();
    deg[root] = 0;
    fa[root][0] = root;
    togo.push(root);
    while(!togo.empty())
    {
        int tmp = togo.front();
        togo.pop();
        for(int i=1;i<DEG;++i)
            fa[tmp][i] = fa[fa[tmp][i-1]][i-1];
        for(int i=head[tmp];i!=-1;i=edges[i].next)
        {
            int v = edges[i].v;
            if(v==fa[tmp][0])   continue;
            deg[v] = deg[tmp] + 1;
            fa[v][0] = tmp;
            togo.push(v);
        }
    }
}

int query_lca(int u, int v)
{
    if(deg[u]>deg[v])   swap(u,v);
    int hu = deg[u], hv = deg[v];
    int tu = u, tv = v;
    for(int det=hv-hu,i=0;det;det>>=1,++i)
        if(det&1)
            tv = fa[tv][i];
    if(tu==tv)  return tu;
    for(int i=DEG-1;i>=0;--i)
    {
        if(fa[tu][i]==fa[tv][i])    continue;
        tu = fa[tu][i];
        tv = fa[tv][i];
    }
    return fa[tu][0];
}

void bfs_dis(int root)
{
    dis[root] = 0;
    while(!togo.empty())    togo.pop();
    togo.push(root);
    flag[root] = 1;
    while(!togo.empty())
    {
        int sz = togo.size();
        for(int t=1;t<=sz;++t)
        {
            int tp = togo.front();
            togo.pop();
            flag[tp] = 1;
            for(int i=head[tp];i!=-1;i=edges[i].next)
            {
                int v= edges[i].v;
                if(!flag[v])
                {
                    dis[v] = dis[tp]+edges[i].cost;
                    togo.push(v);
                }
            }
        }
    }
}

int query_dis(int u, int v)
{
    int lca = query_lca(u,v);
    return dis[u]+dis[v]-2*dis[lca];
}


int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.in","w+",stdout);
    char c;
    ll cc;
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        mapp_init();
        for(int i=0;i<N;++i)
        {
            for(int j=1;j<=M;++j)
            {
                scanf(" %c%lld",&c,&cc);
                if(c!='X')
                {
                    add_edge(i*M+j,i*M+M+j,-1*cc);
                    //add_edge(i*M+M+j,i*M+j,-1*cc);
                }
                scanf(" %c%lld",&c,&cc);
                if(c!='X')
                {
                    add_edge(i*M+j,i*M+j+1,-1*cc);
                    //add_edge(i*M+j+1,i*M+j,-1*cc);
                }
            }
        }
        kruskal();
        memset(flag,0,sizeof(flag));
        bfs_dis(1);
        BFS(1);
        int Q; scanf("%d",&Q);
        while(Q--)
        {
            int xx1, yy1, xx2, yy2;
            scanf("%d%d%d%d",&xx1,&yy1,&xx2,&yy2);
            xx1--;
            xx2--;
            xx1 = xx1*M+yy1;
            xx2 = xx2*M+yy2;
            printf("%d\n",query_dis(xx1,xx2));
        }
    }
}

K Morgana Net(矩阵快速幂)

题目链接
题意:

给定矩阵A,B,求A卷积t次B。

思路:

将卷积运算转化为矩阵快速幂,即对应A的每个元素,都通过其周边元素*B中对应值得来,故把A拍成一维向量,构造一个满足上述运算的矩阵即可。

AC代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <bitset>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;
#define ll long long
#define ld long double
#define pb push_back
#define mp make_pair
#define X  first
#define Y  second
#define REP(i,st,ed)    for(int i=st;i<=ed;++i)
#define IREP(i,st,ed)   for(int i=ed;i>=st;--i)
#define TCASE(T)    cin>>T;while(T--)


const int MAXN = 1000005;
const ll MOD = 1e9+7 ;
const ll INF = 1e16+7;

int _;

using namespace std;

const int demension = 65;

int n, m;

struct Matrix
{
    bool a[demension][demension];
    Matrix()
    {
        memset(a,0,sizeof(a));
    }
    void init()
    {
        memset(a, 0, sizeof(a));
        for(int i=0;i<demension;++i)
            a[i][i] = 1LL;
    }
    void print()
    {
        for(int i=0;i<demension;++i)
        {
            for(int j=0;j<demension;++j)
                cout<<a[i][j]<<" ";
            cout<<endl;
        }
    }
};

Matrix mul(Matrix a, Matrix b)
{
    Matrix ans;
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=n; ++j)
        {
            if(a.a[i][j])
            for(int k=1; k<=n; ++k)
            {
                ans.a[i][k]=ans.a[i][k]^(a.a[i][j]&b.a[j][k]);
            }
        }
    return ans;
}

Matrix qpow(Matrix a, int n)
{
    Matrix ans;
    ans.init();
    while(n)
    {
        //ans.print();
        if(n&1) ans = mul(ans, a);
        a = mul(a, a);
        n >>= 1;
    }
    return ans;
}

Matrix mat;

int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.in","w+",stdout);
    TCASE(_)
    {
        mat.init();
        int N, M, T;
        scanf("%d%d%d",&N,&M,&T);
        Matrix a,b,c;
        int tmp;
        REP(i,1,N)
            REP(j,1,N)
                {
                    scanf("%d",&tmp);
                    a.a[1][(i-1)*N+j] = tmp&1;
                }
        REP(i,1,M)
            REP(j,1,M)
                {
                    scanf("%d",&tmp);
                    b.a[i][j] = tmp&1;
                }
        n=N*N;
        m=M/2;
        REP(i,1,N)
            REP(j,1,N)
                REP(p,i-m,i+m)
                    REP(q,j-m,j+m)
                    {
                        if (p<1 || p>N || q<1 || q>N ) continue;
                        c.a[(p-1)*N+q][(i-1)*N+j]=b.a[p-i+m+1][q-j+m+1];
                    }
        b=qpow(c,T);
        b=mul(a,b);
        int ans=0;
        for (int i=1;i<=n;i++) if (b.a[1][i]) ans++;
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值