Changle training Day6

T1 series

topic

Description [title]

[Input Format]

[Output format]

[Data] scale

As described above.

Resolve

As T1, T4 actually harder than I how to do ...... ...... The following is a giant guy Solution:

I guess you read the explanations estimates do not understand ( manual funny ), together with the code and see, I can not do anything.

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
using namespace std;
int read()
{
    int num=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        num=(num<<1)+(num<<3)+ch-'0';
        ch=getchar();
    }
    return num*w;
}
const int N=400100;
struct rec1{
    int w,pos,num;
}a[N];
struct rec2{
    int x,y,z,num;
}b[N];
struct rec3{
    int tot0;
    long long tot1,tot2;
    rec3 friend operator - (rec3 x,rec3 y)
    {
        return (rec3){x.tot0-y.tot0,x.tot1-y.tot1,x.tot2-y.tot2};
    }
};
int n,q;
long long sum[N*2][3],ans[N];
bool bj[N];
bool cmp1(rec1 x,rec1 y)
{
    return x.w<y.w;
}
bool cmp2(rec2 x,rec2 y)
{
    return x.z<y.z;
}
void insert(int x,int y)
{
    long long g=1ll*y*y;
    for(int i=x;i<=n;i+=(i&-i)) sum[i][0]++,sum[i][1]+=y,sum[i][2]+=g;
}
rec3 find(int x)
{
    rec3 tot=(rec3){0,0,0};
    for(int i=x;i;i-=(i&-i)) tot.tot0+=sum[i][0],tot.tot1+=sum[i][1],tot.tot2+=sum[i][2];
    return tot;
}
void put(long long x)
{
    if(!x){cout<<"0"<<endl;return ;}
    if(x<0) x=-x,cout<<"-";
    int b[20],lenb=0;
    while(x)
    {
        b[++lenb]=x%10;
        x/=10;
    }
    for(int i=lenb;i>=1;i--) cout<<(char)(b[i]+'0');
    cout<<endl;
}
int main()
{
    //freopen("sequence.in","r",stdin);
    //freopen("sequence.out","w",stdout);
    n=read(),q=read();
    for(int i=1;i<=n;i++) a[i].w=read(),a[i].pos=read(),a[i].num=i;
    sort(a+1,a+n+1,cmp1);
    for(int i=1;i<=q;i++) b[i].x=read(),b[i].y=read(),b[i].z=read(),b[i].num=i;
    sort(b+1,b+q+1,cmp2);
    int j=0;
    for(int i=1;i<=q;i++)
    {
        while(j+1<=n&&a[j+1].w<=b[i].z) insert(a[j+1].num,a[j+1].pos),j++;
        rec3 tot=find(b[i].y)-find(b[i].x-1);
        if(!tot.tot0){bj[b[i].num]=1;continue;}
        ans[b[i].num]=tot.tot2*tot.tot0-2*tot.tot1*tot.tot1+tot.tot1*tot.tot1;
    }
    for(int i=1;i<=q;i++)
        if(bj[i]) cout<<"empty"<<endl;
        else put(ans[i]);
    return 0;
    //fclose(stdin);
    //fclose(stdout);
}
View Code

 

 

 

 

 

T2 集合

题目

【题目描述】

给定一个可重集合,一开始只有一个元素0。然后你可以操作若干轮,每一轮,你需要对于集合中的每个元素x进行如下三种操作之一:

1、将x变为x+1。

2、将x分裂为两个非负整数y,z,且满足x=y+z。

3 、什么都不做。

每一轮,集合中的每个元素都必须进行上面三个操作之一。

对于一个最终的集合,你的任务是判断至少进行了多少轮。

【输入格式】

第一行为一个正整数n,表示集合的最终大小。

第二行为n个非负整数,描述集合中的元素。

【输出格式】

输出一个非负整数,为最少的轮数。

【数据规模】

解析

四题中唯一一道送分题,结果看错题目了QAQ。

很显然我们应该尽量把数分得多一些,然后尽量加一。

从零开始推显然不好操作,我们不妨逆着推:

每次把不是零的数都减一,把零两两合并。

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
using namespace std;
int read()
{
    int num=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        num=(num<<1)+(num<<3)+ch-'0';
        ch=getchar();
    }
    return num*w;
}
int n,a[1000100],cnt[1000100],maxn;
long long ans;
int main()
{
    //freopen("multiset.in","r",stdin);
    //freopen("multiset.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        maxn=max(maxn,a[i]);
        cnt[a[i]]++;
    }
    for(int i=1;i<=maxn;i++)
    {
        ans++;
        cnt[0]=(cnt[0]+1)>>1;
        cnt[0]+=cnt[i];
    }
    for(;cnt[0]>1;cnt[0]=(cnt[0]+1)>>1) ans++;
    cout<<ans;
    return 0;
    //fclose(stdin);
    //fclose(stdout);
}
View Code

 

 

 

 

 

T3 迎接仪式

题目

【题目描述】

教主要来C市指导学习工作了。为了迎接教主,在一条道路旁,一群人穿着文化衫站在道路两旁迎接教主,每件文化衫上都印着大字。

一旁的人依次摆出“欢迎欢迎欢迎欢迎……”的大字,但是领队突然发现,另一旁穿着“教”和“主”字文化衫的人却不太和谐。

为了简单描述这个不和谐的队列,我们用“j”替代“教”,“z”替代“主”。而一个“j”与“z”组成的序列则可以描述当前的队列。

为了让教主看得尽量舒服,你必须调整队列,使得“jz”子串尽量多。每次调整你可以交换任意位置上的两个人,也就是序列中任意位置上的两个字母。

而因为教主马上就来了,时间仅够最多作K次调整(当然可以调整不满K次),所以这个问题交给了你。

【输入格式】

第1行包含2个正整数N与K,表示了序列长度与最多交换次数。

第2行包含了一个长度为N的字符串,字符串仅由字母“j”与字母“z”组成,描述了这个序列。

【输出格式】

仅包括一个非负整数,为调整最多K次后最后最多能出现多少个“jz”子串。

【数据规模】

对于10%的数据,有N≤10;

对于30%的数据,有K≤10;

对于40%的数据,有N≤50;

对于100%的数据,有N≤500,K≤100

解析

又是动态规划,令f[i][j][z]表示前i个字符,已经处理了j个'j'和z个'z'。

边界为f[0][0][0]=f[1][0][0]=0。

状态转移方程:

1、不换:f[i][j][z]=f[i-1][j][z]。

2、换:如果a[i-1]为'j'的话,令u=0,否则u=1,如果a[i]为'z'的话,令v=0,否则v=1,

因为如果之前处理过了'j'或'z'的话,就不用增加处理'j'与'z'的数量,反之要增加,故f[i][j][z]=f[i-2][j-u][z-v]。

最后答案为最大的f[n][i][i](i=1-k)。

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
using namespace std;
int read()
{
    int num=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        num=(num<<1)+(num<<3)+ch-'0';
        ch=getchar();
    }
    return num*w;
}
int n,k,maxn,f[505][105][105],l1,l2,u,v;
char a[505];
int main()
{
    //freopen("welcome.in","r",stdin);
    //freopen("welcome.out","w",stdout);
    memset(f,0xcf,sizeof(f));
    f[0][0][0]=0,f[1][0][0]=0;
    n=read(),k=read();
    a[0]='z',a[n+1]='j';
    for(int i=1;i<=n;i++)
    {
        a[i]=getchar();
        if(a[i]=='j') l1++;
        else l2++;
    }
    l1=min(l1,k),l2=min(l2,k);
    for(int i=2;i<=n;i++)
    {
        if(a[i-1]=='j') u=0;
        else u=1;
        if(a[i]=='z') v=0;
        else v=1;
        for(int j=0;j<=l1;j++)
            for(int z=0;z<=l2;z++)
            {
                f[i][j][z]=f[i-1][j][z];//不换
                if(j-u>=0&&z-v>=0) f[i][j][z]=max(f[i][j][z],f[i-2][j-u][z-v]+1);//
            }
    }
    for(int i=0;i<=k;i++) maxn=max(maxn,f[n][i][i]);
    cout<<maxn;
    return 0;
    //fclose(stdin);
    //fclose(stdout);
}
View Code

 

 

 

 

 

T4 益智游戏

题目

【题目描述】

小P和小R在玩一款益智游戏。游戏在一个正权有向图上进行。

小P控制的角色要从A点走最短路到B点,小R控制的角色要从C点走最短路到D点。

一个玩家每回合可以有两种选择,移动到一个相邻节点或者休息一回合。

假如在某一时刻,小P和小R在相同的节点上,那么可以得到一次特殊奖励,但是在每个节点上最多只能得到一次。

求最多能获得多少次特殊奖励。

【输入格式】

第一行两个整数n,m表示有向图的点数和边数。

接下来m行每行三个整数xi,yi,li,表示从xi到yi有一条长度为li的边。

最后一行四个整数A,B,C,D,描述小P的起终点,小R的起终点。

【输出格式】

输出一个整数表示最多能获得多少次特殊奖励。若小P不能到达B点或者小R不能到达D点则输出-1。

【数据规模】

对于30%的数据,满足n≤50

对于60%的数据,满足n≤1000,m≤5000

对于100%的数据,满足n≤50000,m≤200000,1≤li≤500000000

解析

这题正解居然是四遍dijkstra+topu排序,恐怖如斯,不说了,直接扔大佬题解:

(1)特殊奖励的点一定是连续的

(2)若s-->x+(x,y)+y-->t = s-->t 则(x,y)在s到t的最短路上

(3)所有在A-->B,C-->D的最短路上的边构成一个有向无环图

在正向图上求A,C出发的最短路

在反向图上求到达B,D的最短路

最短路可以用dijkstra+优先队列

筛选出在A-->B,C-->D的最短路上的边作为新图

对新图拓扑排序+DP求最长路

时间复杂度(MlogN)

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
using namespace std;
long long read()
{
    long long num=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        num=(num<<1)+(num<<3)+ch-'0';
        ch=getchar();
    }
    return num*w;
}
const int N=50010;
const int M=200010;
struct rec{
    int to,next;
    long long l;
}edge1[M],edge2[M];
int n,m,cnt,head1[N],head2[N],in[N],f[N],ans;
long long d1[N],d2[N],d3[N],d4[N];
bool vis[N];
void add1(int x,int y,int l)
{
    edge1[++cnt].to=y;
    edge1[cnt].l=l;
    edge1[cnt].next=head1[x];
    head1[x]=cnt;
    edge2[cnt].to=x;
    edge2[cnt].l=l;
    edge2[cnt].next=head2[y];
    head2[y]=cnt;
}
void add2(int x,int y)
{
    edge2[++cnt].to=y;
    edge2[cnt].next=head2[x];
    head2[x]=cnt;
}
void dijkstra(int t,long long *d,int *head,rec *edge)
{
    for(int i=1;i<=n;i++) d[i]=0x7f7f7f7f7f7f7f7f;
    memset(vis,false,sizeof(vis));
    priority_queue< pair<long long,int> > q;
    d[t]=0,q.push(make_pair(0,t));
    while(q.size())
    {
        int now=q.top().second;
        q.pop();
        if(vis[now]) continue;
        vis[now]=true;
        for(int i=head[now];i;i=edge[i].next)
        {
            int next=edge[i].to;
            long long l=edge[i].l;
            if(d[next]>d[now]+l)
            {
                d[next]=d[now]+l;
                q.push(make_pair(-d[next],next));
            }
        }
    }
}
void topu_sort()
{
    queue<int> q;
    for(int i=1;i<=n;i++)
        if(!in[i]) q.push(i);
    while(q.size())
    {
        int now=q.front();
        q.pop();
        for(int i=head2[now];i;i=edge2[i].next)
        {
            int next=edge2[i].to;
            f[next]=max(f[next],f[now]+1);
            ans=max(ans,f[next]);
            in[next]--;
            if(!in[next]) q.push(next);
        }
    }
}
int main()
{
    //freopen("game.in","r",stdin);
    //freopen("game.in","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        long long l=read();
        add1(x,y,l);
    }
    int a=read(),b=read(),c=read(),d=read(),k=0;
    dijkstra(a,d1,head1,edge1),dijkstra(b,d2,head2,edge2);
    dijkstra(c,d3,head1,edge1),dijkstra(d,d4,head2,edge2);
    if(d1[b]==0x7f7f7f7f7f7f7f7f||d3[d]==0x7f7f7f7f7f7f7f7f)
    {
        cout<<"-1";
        return 0;
    }
    for(int i=1;i<=n;i++)
        if(d1[i]+d2[i]==d1[b]&&d3[i]+d4[i]==d3[d])
        {
            k=1;
            break;
        }
    memset(edge2,0,sizeof(edge2));
    memset(head2,0,sizeof(head2));
    cnt=0;
    for(int i=1;i<=n;i++)
        for(int j=head1[i];j;j=edge1[j].next)
        {
            int next=edge1[j].to;
            if(d1[i]+d2[next]+edge1[j].l==d1[b]&&d3[i]+d4[next]+edge1[j].l==d3[d])
            {
                in[next]++;
                add2(i,next);
            }
        }
    topu_sort();
    cout<<ans+k;
    return 0;
    //fclose(stdin);
    //fclose(stdout);
}
View Code

Guess you like

Origin www.cnblogs.com/I-Love-You-520/p/11255959.html