ACM-ICPC 2018 徐州赛区网络赛

学长们还是太强了,膜拜,虽然和清华北大那些比不了,但是还是比较强的,毕竟他们只有三个人,写了7题

下面是学长们的代码

 

A题

 

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^k2k masks numbered from 0,1,\cdots,0,1,⋯, 2^k - 12k−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.

 

就是一道递推题,但是我就是一直wa,结果学长上来1A

学长的代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int maxn=1e6+5;
long long two[maxn];
void init()
{
    two[0]=1;
    for(int i=1;i<maxn;i++)two[i]=two[i-1]*2%mod;
}
long long ans[maxn];
int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int N,k;
        scanf("%d %d",&N,&k);
        ans[1]=two[k];
        long long tmp1=((two[k]-1)%mod+mod)%mod;
        long long tmp2=((two[k]-2)%mod+mod)%mod;
        ans[2]=ans[1]*tmp1%mod;
        for(int i=3;i<=N;i++)
        {
            ans[i]=ans[i-2]*tmp1%mod;
            long long tmp=((ans[i-1]-ans[1])%mod+mod)%mod;
            tmp=tmp*tmp2%mod;
            ans[i]=(ans[i]+tmp)%mod;
        }
        printf("%lld\n",ans[N]);
    }
    return 0;
}

不是那么好理解,我感觉我的思路好理解一些

赛后重新写了一遍,过了

网上有个人和我思路一模一样,大家听不懂我讲的可以参考别人的

https://blog.csdn.net/m0_37611893/article/details/82560420

下面我来讲一下我的思路:

首先要知道,每一种面罩都只有一种面罩与他互斥,就是同或为0

 

然后我也是递推,分三种,good,bad,neutral,三个数组递推,

比如说我0开头,0就是good,与0互斥的就是bad,剩下的就是neutral

我们再画一下图,发现之间的关系,就可以递推了

good由good和neutral产生

所以 good[i] = good[i-1]+neutral[i-1];

bad由bad和neutra产生

所以bad[i] = bad[i-1]+neutral[i-1];

(前两种都只产生一个)

neutral有点不同

它由good,bad和neutral产生

good产生2^k-2个,bad产生2^k-2个

neutral产生2^k-3个

然后递推

t1 = 2^k-2;

t2 = 2^k-3;

g[i] = g[i-1]+n[i-1];
n[i] = t1*g[i-1] + t2*n[i-1] + t1*b[i-1];
b[i] = n[i-1]+b[i-1];

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<time.h>
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
using namespace std;
typedef long long ll;
const int maxn =1e6+5;
const ll mod=1000000007;
ll g[maxn],n[maxn],b[maxn];

int main()
{
   // freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);

    int nn;
    ll k;
    int T;
    cin>>T;
    while(T--)
    {
        cin>>nn>>k;
        ll tt = k;
        g[1]=1,b[1]=n[1]=0;
        ll r=1;
        ll base =2;
        while(k)
        {
            if(k&1)
                r=(r*base)%mod;
            base =(base*base)%mod;
            k = k/2;
        }
        r = r%mod;
        ll t1=(r-2+mod)%mod;
        ll t2 =(r-3+mod)%mod;
        for(int i=2;i<=nn;i++)
            {
                 g[i] = ( g[i-1]+n[i-1] )%mod;
                 n[i] =( ( (t1*g[i-1])%mod+(t2*n[i-1])%mod )%mod+(t1*b[i-1])%mod)%mod;
                 b[i] =( n[i-1]+b[i-1] )%mod;
            }
        
        cout<< (  ( (g[nn]+n[nn]   ) %mod)*r )%mod<<endl;
    }
    return 0;
}

/*
10000

5646 2313
6545 56446
21313 45646
1321 4897
3213 6987
31313 1111
54646 666
33333 4444
2222 111
16346 31321



*/

B题属于博弈的题

 

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<k≤100), represents the number of choices, the initial score, the minimum score required to enter a good ending, and the highest score required to enter a bad ending, respectively.

Each of the next nn lines contains three integers a,b,ca,b,c(a\ge 0a≥0 , b\ge0b≥0 ,c=0c=0 or c=1c=1),indicates the options that appear in this selection,in which a=0a=0 means there is no option to increase the score in this selection, a>0a>0 means there is an option in this selection to increase the score by aa ; b=0b=0 means there is no option to decrease the score in this selection, b>0b>0 means there is an option in this selection to decrease the score by bb; c=0c=0 means there is no option to multiply the score by -1−1 in this selection , c=1c=1 means there is exactly an option in this selection to multiply the score by -1−1. It is guaranteed that a,b,ca,b,c are not equal to 00 at the same time.

 

学长们用dp写的,然而我把这个当成极大极小搜索了,结果一直超时

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
struct node
{
    int a,b,c;
    node(int a,int b,int c):a(a),b(b),c(c) {}
    node() {}
} nodes[maxn];
int dp[maxn][300];
int offset=150;
int n,m,k,l;
int dfs(int d,int s)
{
    if(dp[d][s]!=-1)return dp[d][s];
    int a=nodes[d].a,b=nodes[d].b,c=nodes[d].c;
    if(d==n+1)
    {
        if(s>=k)return 1;
        else if(s<=l)return 0;
        return 2;
    }
    int flag=0;
    if(d%2)
    {
        if(a!=0)
        {
            int nxts=min(100+offset,s+a);
            int tmp=dfs(d+1,nxts);
            if(tmp==1)
                return dp[d][s]=1;
            if(tmp==2)
                flag=1;
        }
        if(b!=0)
        {
            int nxts=max(-100+offset,s-b);
            int tmp=dfs(d+1,nxts);
            if(tmp==1)
                return dp[d][s]=1;
            if(tmp==2)
                flag=1;
        }
        if(c!=0)
        {
            int nxts=2*offset-s;
            int tmp=dfs(d+1,nxts);
            if(tmp==1)
                return dp[d][s]=1;
            if(tmp==2)
                flag=1;
        }
        if(flag)
            return dp[d][s]=2;
        return dp[d][s]=0;
    }
    else
    {
        if(a!=0)
        {
            int nxts=min(100+offset,s+a);
            int tmp=dfs(d+1,nxts);
            if(tmp==0)
                return dp[d][s]=0;
            if(tmp==2)
                flag=1;
        }
        if(b!=0)
        {
            int nxts=max(-100+offset,s-b);
            int tmp=dfs(d+1,nxts);
            if(tmp==0)
                return dp[d][s]=0;
            if(tmp==2)
                flag=1;
        }
        if(c!=0)
        {
            int nxts=2*offset-s;
            int tmp=dfs(d+1,nxts);
            if(tmp==0)
                return dp[d][s]=0;
            if(tmp==2)
                flag=1;
        }
        if(flag)
            return dp[d][s]=2;
        return dp[d][s]=1;
    }
}

int main()
{
    memset(dp,-1,sizeof(dp));
    scanf("%d %d %d %d",&n,&m,&k,&l);
    k+=offset;
    l+=offset;
    int a,b,c;
    for(int i=1; i<=n; i++)
    {
        scanf("%d %d %d",&a,&b,&c);
        nodes[i]=node(a,b,c);
    }

    int tmp=dfs(1,offset+m);
    if(tmp==1)
        puts("Good Ending");
    else if(tmp==0)
        puts("Bad Ending");
    else puts("Normal Ending");
}

后来我用记忆化搜索写的,就过了,发现好简单,怎么搞的

我的代码还是比较简单的

dp[i][j]存值,i表示到达这一层的分数,j表示层数,一共是1--n层,每一层有三种状态。

现在怎么觉得这道题有点简单啊

下面是我的代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>

typedef long long ll;
using namespace std;
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define fork(l,r) for( int k = l ; k <= r ; k++ )
#define mem(a,val) memset(a,val,sizeof a)
#define inf 0x3f3f3f3f
const int maxn = 1e3+4;
int n,first_score,up,down;
int dp[214][maxn];
struct spe
{
    int a,b,c;
};
spe p[maxn];
void change( int &x )
{
    if( x > 100 )
        x = 100;
    if( x < -100 )
        x = -100;
}
int f( int a,int b,int i )
{
    if( i&1 )
        return max(a,b);
    else return min(a,b);
}
int dfs( int cnt,int score )
{
    change(score);
    if( cnt == n+1 )
        return score;
    if( dp[score+100][cnt] != inf )
        return dp[score+100][cnt];
    int ans = inf;
    if( cnt&1 )
        ans = -ans;
    if( p[cnt].a > 0 )
    {
        ans = f(ans,dfs(cnt+1,score+p[cnt].a ),cnt);
        change(ans);
    }
    if( p[cnt].b > 0 )
    {
        ans = f(ans,dfs(cnt+1,score-p[cnt].b ),cnt );
        change(ans);
    }
    if( p[cnt].c > 0 )
    {
        ans = f(ans,dfs(cnt+1,-score),cnt );
        change(ans);
    }
    dp[score+100][cnt] = ans;
    return ans;
}
int main()
{
    while( scanf("%d %d %d %d",&n,&first_score,&up,&down) == 4 )
    {
        mem(dp,inf);
        fori(1,n)
            scanf("%d %d %d",&p[i].a,&p[i].b,&p[i].c);

        int t = dfs(1,first_score);
        //cout<<t<<endl;
        if( t >= up )
            puts("Good Ending");
        else if( t <= down )
            puts("Bad Ending");
        else puts("Normal Ending");
    }

    return 0;
}
/*




*/

 

C题是个求期望的题,但是学长他们没做,可能是时间不够,但是我们队看了,不过样例都凑不出来,后来补了上来,是一道模拟题,其实感觉还比较好写吧,就是题目超级难理解,还有坑爹的问答区,我真想不通这个*和#跟买彩票前几位知道有什么关系

 

先说一下样例二吧

4313.16666667 = ( 10000+10000+  3600+119 +  1080+1080  )/6

就是分别枚举*号,这个还好,但是对于#的处理是:

它只能选一行或一列或斜着的,所以只能对一行一列的值进行累加了比较,由于有多种情况,所以多种情况累加到相应的行或列

,重要的就是累加,累加出来的最大的,就是要选的那一行或那一列

 

所以我们要分别枚举*和#,注意,*和#的处理方法是不一样的,而且是先枚举#,后枚举#

 

Morgana is playing a game called cacti lottery. In this game, morgana has a 3 \times 33×3 grid graph, and the graph is filled with 11 ~ 99 , each number appears only once. The game is interesting, he doesn't know some numbers, but there are also some numbers he knows but don't want to tell you.

Now he should choose three grids, these three grids should be in the same column or in the same row or in the diagonal line. Only after this choice, can he know all numbers in the grid graph. Then he sums the three numbers in the grids he chooses, get the reward as follows:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define mem(a,val) memset(a,val,sizeof a)
#define inf 0x3f3f3f3f
using namespace std;
char s[8][8];
int counter[14];
int cnt;
int remain[15];
bool vis[15];
int starnum,num;
vector<int> star;
vector<int> rest;
double fac[14];
double val[15];
double ans;
double value[100];
void calculate( int m[5][5] )
{
    int pos = 0;
    fori(1,3)
        forj(1,3)
            if( s[i][j] == '#' )
                m[i][j] = rest[pos++];

    fori(1,3)
        val[i] += value[ m[i][1]+m[i][2]+m[i][3] ];
    fori(4,6)
        val[i] += value[ m[1][i-3]+m[2][i-3]+m[3][i-3] ];
    val[7] += value[ m[1][1]+m[2][2]+m[3][3] ];
    val[8] += value[ m[3][1]+m[2][2]+m[1][3] ];
}
void fill_rest( int time,int m[5][5] )
{
    if( time == num )
    {
        calculate(m);
        return;
    }
    for( int i = 1 ; i < cnt ; i++ )
    {
        if( !vis[i] )
        {
            vis[i] = true;
            rest.push_back(remain[i]);
            fill_rest(time+1,m);
            rest.pop_back();
            vis[i] = false;
        }
    }

}
double getval( )
{
    int m[5][5];

    int pos = 0;
    fori(1,3)
        forj(1,3)
            if( s[i][j] == '*' )
                m[i][j] = star[pos++];
            else if( s[i][j] != '#' )
                m[i][j] = s[i][j]-'0';
    mem(val,0);
    fill_rest(0,m);
    double ma = 0;
    fori(1,8)
        ma = max(ma,val[i]);
    return ma/fac[num];

}
void fill_star( int time )
{
    if( time == starnum )
    {
        ans += getval();
        return;
    }
    for( int i = 1 ; i < cnt ; i++ )
    {
        if( !vis[i] )
        {
            vis[i] = true;
            star.push_back(remain[i]);
            fill_star(time+1);
            star.pop_back();
            vis[i] = false;
        }
    }
}
void init()
{

    value[6]=10000;
    value[7]=36;
    value[8]=720;
    value[9]=360;
    value[10]=80;
    value[11]=252;
    value[12]=108;
    value[13]=72;
    value[14]=54;
    value[15]=180;
    value[16]=72;
    value[17]=180;
    value[18]=119;
    value[19]=36;
    value[20]=360;
    value[21]=1080;
    value[22]=144;
    value[23]=1800;
    value[24]=3600;
    fac[1] = fac[0] = 1;
    for( int i = 2 ; i <= 9 ; i++ )
    {
        fac[i] = fac[i-1]*(double)i;
    }
}
int main()
{
    init();
    int T;
    scanf("%d",&T);
    while( T-- )
    {
        cnt = 1;
        mem(counter,0);
        mem(vis,false);
        star.clear();
        rest.clear();
        starnum = 0;
        num = 0;
        ans = 0;

        fori(1,3)
        {
            scanf("%s",s[i]+1);
            forj(1,3)
            {
                int t = s[i][j]-'0';
                if( t >= 1 && t <= 9 )
                    counter[t]++;
                else if( s[i][j] == '*' )
                    starnum++;
                else if( s[i][j] == '#' )
                    num++;
            }
        }
        fori(1,9)
            if( counter[i] == 0 )
                remain[cnt++] = i;
        fill_star(0);

        cnt--;

        double temp = 1;
        for( int i = cnt ; i >= cnt-starnum+1 ; i-- )
            temp = temp*(double)i;
        ans = ans/temp;
        printf("%.8f\n",ans);
    }
    return 0;
}
/*
5

###
###
###

***
***
***

134
***
***

542
***
***

1**
**4
***


*/

 

F题

Morgana is learning computer vision, and he likes cats, too. One day he wants to find the cat movement from a cat video. To do this, he extracts cat features in each frame. A cat feature is a two-dimension vector <xx, yy>. If x_ixi​= x_jxj​ and y_iyi​ = y_jyj​, then <x_ixi​, y_iyi​> <x_jxj​, y_jyj​> are same features.

So if cat features are moving, we can think the cat is moving. If feature <aa, bb> is appeared in continuous frames, it will form features movement. For example, feature <aa , bb > is appeared in frame 2,3,4,7,82,3,4,7,8, then it forms two features movement 2-3-42−3−4 and 7-87−8 .

Now given the features in each frames, the number of features may be different, Morgana wants to find the longest features movement.

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef pair<int,int>pii;
map<pii,int>M[2];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        M[0].clear();
        M[1].clear();
        int N;
        scanf("%d",&N);
        int now=0;
        int ans=1;
        for(int i=1;i<=N;i++)
        {
            M[now].clear();
            int k;
            scanf("%d",&k);
            int a,b;
            for(int j=1;j<=k;j++)
            {
                scanf("%d %d",&a,&b);
                pii tmp=pii(a,b);
                if(M[now^1].count(tmp))
                {
                    M[now][tmp]=M[now^1][tmp]+1;
                    ans=max(ans,M[now][tmp]);
                }
                else
                {
                    M[now][tmp]=1;
                }
            }
            now^=1;
        }
        printf("%d\n",ans);
    }
    return 0;



}

 

G题

G题是一道思维题,学长的代码短的很

There's a beach in the first quadrant. And from time to time, there are sea waves. A wave ( xx , yy ) means the wave is a rectangle whose vertexes are ( 00 , 00 ), ( xx , 00 ), ( 00 , yy ), ( xx , yy ). Every time the wave will wash out the trace of former wave in its range and remain its own trace of ( xx , 00 ) -> ( xx , yy ) and ( 00 , yy ) -> ( xx , yy ). Now the toad on the coast wants to know the total length of trace on the coast after n waves. It's guaranteed that a wave will not cover the other completely.

Input

The first line is the number of waves n(n \le 50000)n(n≤50000).

The next nn lines,each contains two numbers xx yy ,( 0 < x0<x , y \le 10000000y≤10000000 ),the ii-th line means the ii-th second there comes a wave of ( xx , yy ), it's guaranteed that when 1 \le i1≤i , j \le nj≤n ,x_i \le x_jxi​≤xj​ and y_i \le y_jyi​≤yj​ don't set up at the same time.

Output

An Integer stands for the answer.

Hint:

As for the sample input, the answer is 3+3+1+1+1+1=103+3+1+1+1+1=10

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+5;
int x[maxn],y[maxn];
set<int>S;
int n;
long long solve(int *num)
{
    long long res=0;
    S.clear();
    S.insert(0);
    for(int i=n;i>=1;i--)
    {
        int thenum=num[i];
        if(S.empty())
        {
            res+=thenum;
            S.insert(thenum);
            continue;
        }
        auto it=S.upper_bound(thenum);
        it--;
        res+=thenum-(*it);
        S.insert(thenum);
    }
    return res;
}

int main()
{

    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d %d",&x[i],&y[i]);
    long long ans=solve(x);
    ans+=solve(y);
    printf("%lld\n",ans);
}

而我是用线段树写的,感觉就是麻烦一点,不过也是过了,虽然是赛后过的

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<cmath>
#include<time.h>
#include<map>
typedef long long ll;
using namespace std;
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define fork(l,r) for( int k = l ; k <= r ; k++ )
#define mem(a,val) memset(a,val,sizeof a)
#define inf 0x3f3f3f3f
#define lef rt<<1
#define rig rt<<1|1
#define mid (l+r)>>1
const int maxn = 5e5+5;     //老老实实开5e4+5 的数组runtime_error  可能数据有问题
int cpyx[maxn],cpyy[maxn];
struct spe
{
    ll x,y;
};
spe p[maxn];
int n;
ll tree1[maxn<<2],tree2[maxn<<2];
int L,R;

ll query_max( int l,int r,int rt,ll tree[] )
{
    if( l >= L && r <= R )
        return tree[rt];
    int m = mid;
    ll ans = 0;
    if( m >= L )
        ans = max(ans,query_max(l,m,lef,tree) );
    if( m < R )
        ans = max(ans,query_max(m+1,r,rig,tree) );
    return ans;
}
void update_point( int l,int r,int rt,int pos,ll val,ll tree[] )
{
    if( l == r )
    {
        tree[rt] = val;
        return;
    }
    int m = mid;
    if( m >= pos )
        update_point(l,m,lef,pos,val,tree);
    else update_point(m+1,r,rig,pos,val,tree);

    tree[rt] = max(tree[lef],tree[rig]);
}
int main()
{
    
    while( scanf("%d",&n) == 1 )
    {
        mem(tree1,0);
        mem(tree2,0);
        int cnt = 1,xnum,ynum;
        fori(1,n)
        {
            scanf("%lld %lld",&p[i].x,&p[i].y);
            cpyx[cnt++] = p[i].x;
            cpyy[cnt++] = p[i].y;
        }
        sort(cpyx+1,cpyx+cnt);
        sort(cpyy+1,cpyy+cnt);
        xnum = unique(cpyx+1,cpyx+cnt)-cpyx-1;
        ynum = unique(cpyy+1,cpyy+cnt)-cpyy-1;
        int x,y;
        ll ans = 0;
        for( int i = n ; i >= 1 ; i-- )
        {
            x = lower_bound(cpyx+1,cpyx+xnum+1,p[i].x)-cpyx;
            L = x,R = xnum;
            ll ma = query_max(1,xnum,1,tree1);
            if( p[i].y > ma )
                ans += p[i].y-ma;
            update_point(1,xnum,1,x,p[i].y,tree1);
            //cout<<" after "<<ans<<endl;
            y = lower_bound(cpyy+1,cpyy+ynum+1,p[i].y)-cpyy;
            L = y,R = ynum;
            ma = query_max(1,ynum,1,tree2);
            if( p[i].x > ma )
                ans += p[i].x-ma;
            update_point(1,ynum,1,y,p[i].x,tree2);
            //cout<<" after "<<ans<<endl;
            //
        }
        printf("%lld\n",ans);
    }
    return 0;
}
/*
6
3 3333
21654 54131
5413213 56464
1313 654654
5564 6543
4894 21313


*/

 

H题是线段树,其实也可以用树状数组

就是普通的点更新和区间求和,建两颗树,一颗乘以权值,另一颗不乘,两颗同时更新,求和的时候减一个东西就行了

Ryuji is not a good student, and he doesn't want to study. But there are n books he should learn, each book has its knowledge a[i]a[i].

Unfortunately, the longer he learns, the fewer he gets.

That means, if he reads books from ll to rr, he will get a[l] \times L + a[l+1] \times (L-1) + \cdots + a[r-1] \times 2 + a[r]a[l]×L+a[l+1]×(L−1)+⋯+a[r−1]×2+a[r] (LL is the length of [ ll, rr ] that equals to r - l + 1r−l+1).

Now Ryuji has qq questions, you should answer him:

11. If the question type is 11, you should answer how much knowledge he will get after he reads books [ ll, rr ].

22. If the question type is 22, Ryuji will change the ith book's knowledge to a new value.

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
#define lowbit(x) x&-x
long long sum1[maxn],sum2[maxn];
void add(long long *sum,int x,long long val)
{
    while(x<maxn)
    {
        sum[x]+=val;
        x+=lowbit(x);
    }
}

long long query(long long *sum,int x)
{
    long long res=0;
    while(x)
    {
        res+=sum[x];
        x-=lowbit(x);
    }
    return res;
}

long long a[maxn];
int n,q;
long long ask(int l,int r)
{
    int len=r-l+1;
    long long res=0;
    long long tmp=query(sum1,r)-query(sum1,l-1);
    long long tmp2;
    tmp=tmp*len;
    res+=tmp;
    tmp=query(sum2,r)-query(sum2,l);
    tmp2=query(sum1,r)-query(sum1,l);
    tmp=tmp-tmp2*l;
    res-=tmp;
    return res;
}

void change(int x,long long val)
{
    add(sum1,x,val-a[x]);
    add(sum2,x,(val-a[x])*x);
    a[x]=val;
}

int main()
{

    scanf("%d %d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        add(sum1,i,a[i]);
        add(sum2,i,a[i]*i);
    }
    int x,y,z;
    while(q--)
    {
        scanf("%d %d %d",&x,&y,&z);
        if(x==1)
        {
            printf("%lld\n",ask(y,z));
        }
        else
        {
            change(y,z);
        }
    }
    return 0;




}

I题签到题

Mur loves hash algorithm, and he sometimes encrypt another one's name, and call him with that encrypted value. For instance, he calls Kimura KMR, and calls Suzuki YJSNPI. One day he read a book about SHA-256256 , which can transit a string into just 256256 bits. Mur thought that is really cool, and he came up with a new algorithm to do the similar work. The algorithm works this way: first we choose a single letter L as the seed, and for the input(you can regard the input as a string ss, s[i]s[i] represents the iith character in the string) we calculates the value(|(int) L - s[i]|∣(int)L−s[i]∣), and write down the number(keeping leading zero. The length of each answer equals to 22because the string only contains letters and numbers). Numbers writes from left to right, finally transfer all digits into a single integer(without leading zero(ss)). For instance, if we choose 'z' as the seed, the string "oMl" becomes "1111 4545 1414".

It's easy to find out that the algorithm cannot transfer any input string into the same length. Though in despair, Mur still wants to know the length of the answer the algorithm produces. Due to the silliness of Mur, he can even not figure out this, so you are assigned with the work to calculate the answer.

Input

First line a integer TT , the number of test cases (T \le 10)(T≤10).

For each test case:

First line contains a integer NN and a character zz, (N \le 1000000)(N≤1000000).

Second line contains a string with length NN . Problem makes sure that all characters referred in the problem are only letters.

Output

A single number which gives the answer.

样例输入复制

2
3 z
oMl
6 Y
YJSNPI

样例输出复制

6
10
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
char s[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int N;
        char z[3];
        scanf("%d %s",&N,z);
        scanf("%s",s);
        int ans=0,flag=0;
        for(int i=0;i<N;i++)
        {
            int num=z[0]-s[i];
            if(flag)ans+=2;
            else if(!flag&&num)
            {
                flag=1;
                if(num<10)ans++;
                else ans+=2;
            }
        }
        if(ans==0)ans=1;
        printf("%d\n",ans);
    }
    return 0;



}

 

J题

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.

#include<bits/stdc++.h>
using namespace std;
#define time te
const int maxn = 250000+100;

const int maxm = maxn*4;
typedef pair<int,int> pii;
vector<pii >V[maxn];
struct Edge
{
	int from, to, dist;
	Edge(int _f,int _t,int _d):from(_f),to(_t),dist(_d){}
	Edge(){}
}edges[maxm];
int tot;
void addedge(int u, int v, int dist)
{
	edges[tot++] = Edge(u, v, dist);
}
int f[maxn], e[maxm];
bool cmp(int a, int b)
{
	return edges[a].dist < edges[b].dist;
}
int find(int a) { return a == f[a] ? a : f[a] = find(f[a]); }
int kruskal(int n)
{
	for (int i = 0;i < n;i++)f[i] = i;
	for (int i = 0;i < tot;i++)e[i] = i;
	sort(e, e + tot, cmp);
	int num = 0;
	long long ans = 0;
	for (int i = 0;i < tot;i++)
	{
		if (num == n - 1)break;
		int u = edges[e[i]].from, v = edges[e[i]].to, dis = edges[e[i]].dist;
		int rootu = find(u), rootv = find(v);
		if (rootu != rootv) { f[rootu] = rootv; ans += dis; num++; V[u].push_back(pii(v,1));V[v].push_back(pii(u,1));}
		else continue;
	}
	if(num<n-1)return -1;
	return ans;
}
//
long long d[maxn];
int dp[maxn][20];
int dep[maxn];
int l[maxn],r[maxn];
int time;
void dfs(int u,int pre,long long dis)
{
    d[u]=dis;
    dp[u][0]=pre;
    ++time;
    l[u]=time;
    for(int i=0;i<V[u].size();i++)
    {
        pii x=V[u][i];
        int v=x.first,w=x.second;
        if(v==pre)continue;
        dep[v]=dep[u]+1;
        dfs(v,u,dis+w);
    }
    r[u]=time;
}

void rmq(int n)
{
    for(int i=1;i<20;i++)
        for(int j=0;j<n;j++)
        {
            if((1<<i)>dep[j])continue;
            int k=dp[j][i-1];dp[j][i]=dp[k][i-1];
        }
}

int query(int x,int y)
{
    if(dep[x]>dep[y])swap(x,y);
    for(int j=19;j>=0&&dep[x]!=dep[y];j--)
    {
        if(dep[y]-(1<<j)<dep[x])continue;
        y=dp[y][j];
    }

    if(x==y)return x;
    for(int j=19;j>=0;j--)
    {
        if(dep[x]-(1<<j)<0||dp[x][j]==dp[y][j])continue;
        x=dp[x][j],y=dp[y][j];
    }
    return dp[x][0];
}
long long getdis(int u,int v)
{
    long long res=0;
    int lca=query(u,v);
    res+=d[u];
    res+=d[v];
    res-=2LL*(d[lca]);
    return res;
}
int main()
{
    int N,M;
    scanf("%d %d",&N,&M);
    char s[3];
    int num;
    for(int i=0;i<N*M;i++)
    {
        int nowx=i/M;
        int nowy=i%M;
        for(int j=1;j<=2;j++)
        {
            scanf("%s %d",s,&num);
            if(s[0]=='X')continue;
            if(s[0]=='D')
            {
                int nxtx=nowx+1;
                int nxty=nowy;
                int thenum=nxtx*M+nxty;
                addedge(i,thenum,-num);
                addedge(thenum,i,-num);
            }
            else
            {
                int nxtx=nowx;
                int nxty=nowy+1;
                int thenum=nxtx*M+nxty;
                addedge(i,thenum,-num);
                addedge(thenum,i,-num);
            }
        }
    }
    kruskal(N*M);
    dfs(0,-1,0);
    rmq(N*M);
    int Q;
    scanf("%d",&Q);
    int x1,y1,x2,y2;
    while(Q--)
    {
        scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
        x1--,y1--,x2--,y2--;
        int u=x1*M+y1;
        int v=x2*M+y2;
        printf("%lld\n",getdis(u,v));
    }
    return 0;
}

 

发布了75 篇原创文章 · 获赞 113 · 访问量 8万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览