10.5考试总结

来源:互联网 发布:网络用语2016最新 编辑:程序博客网 时间:2024/06/01 22:21

B组:

命运

这里写图片描述
这里写图片描述

50分:最小生成树,每两个点连个边
60分(考试分数):当只有1维时,只需对所有点坐标从小到大排序,选相邻的两个点连边即可
100分:发现若答案存在某条边U>V则U和V按某一维排序一定是挨着的,则每次对于这五维排序,对挨着的两个点连边做最小生成树即可

#include<algorithm>#include<ctype.h>#include<cstdio>#define N 100020using namespace std;inline int read(){    int x=0,f=1;char c;    do {c=getchar();if(c=='-') f=-1;} while(!isdigit(c));    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));    return x*f;}int n,k,top;long long ans;int f[N];struct Point{    int pos[7],bh;}a[N];struct Edge{    int x,y,k;    Edge(int _=0,int __=0,int ___=0):x(_),y(__),k(___){}}q[1000050];inline void add(int x,int y,int k){    q[++top]=Edge(x,y,k);}inline int abs(int a){return a>0?a:-a;}int find(int k){return f[k]==k?f[k]:f[k]=find(f[k]);}inline void link(int x,int y){    int fx=find(x),fy=find(y);    f[fx]=fy;}inline bool cmp(Edge a,Edge b){return a.k<b.k;}inline bool cmp1(Point a,Point b){return a.pos[1]<b.pos[1];}inline bool cmp2(Point a,Point b){return a.pos[2]<b.pos[2];}inline bool cmp3(Point a,Point b){return a.pos[3]<b.pos[3];}inline bool cmp4(Point a,Point b){return a.pos[4]<b.pos[4];}inline bool cmp5(Point a,Point b){return a.pos[5]<b.pos[5];}inline void solve(){    for(int i=1;i<=k;i++){        if(i==1)sort(a+1,a+n+1,cmp1);        if(i==2)sort(a+1,a+n+1,cmp2);        if(i==3)sort(a+1,a+n+1,cmp3);        if(i==4)sort(a+1,a+n+1,cmp4);        if(i==5)sort(a+1,a+n+1,cmp5);//按照5维排序        for(int j=2;j<=n;j++){//连边,注意编号可能被打乱,要记录一下            add(a[j-1].bh,a[j].bh,abs(a[j].pos[i]-a[j-1].pos[i]));        }    }    sort(q+1,q+top+1,cmp);    for(int i=1;i<=n;i++) f[i]=i;//最小生成树    for(int i=1,cnt=0;i<=top&&cnt<=n-1;i++){        int fx=find(q[i].x),fy=find(q[i].y);        if(fx==fy) continue;        link(fx,fy);        ans+=q[i].k;        cnt++;    }    printf("%lld",ans);}int main(){    n=read();k=read();    for(int i=1;i<=n;i++)        for(int j=1;j<=k;j++)            a[i].pos[j]=read(),a[i].bh=i;    solve();return 0;}

幻想

这里写图片描述
这里写图片描述

spfa,disi,j表示到点i用了j次更改权值的机会,转移很好想吧…

#include<algorithm>#include<ctype.h>#include<cstdio>#include<queue>#define N 10020#define M 2000200#define int long long#define INF 214748364700000000llusing namespace std;inline int read(){    int x=0,f=1;char c;    do {c=getchar();if(c=='-') f=-1;} while(!isdigit(c));    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));    return x*f;}queue<int>q;int n,m,k,x,y,z,s,t,top;int Dis[N],fir[N];struct Edge{    int nex,to,k;    Edge(int _=0,int __=0,int ___=0):to(_),nex(__),k(___){}}nex[M];inline void add(int x,int y,int k){    nex[++top]=Edge(y,fir[x],k);    fir[x]=top;}bool b[N];inline bool spfa1(){    while(!q.empty()) q.pop();    for(int i=1;i<=n;i++) Dis[i]=INF,b[i]=false;    Dis[s]=0;q.push(s);b[s]=true;    while(!q.empty()){        int x=q.front();q.pop();b[x]=false;        for(int i=fir[x];i;i=nex[i].nex)            if(Dis[nex[i].to]>Dis[x]+nex[i].k){                Dis[nex[i].to]=Dis[x]+nex[i].k;                if(!b[nex[i].to]){                    b[nex[i].to]=true;                    q.push(nex[i].to);                }            }    }    return Dis[t]==INF;}int dis[N][55],ans;bool d[N][55];inline void spfa(){    while(!q.empty()) q.pop();    for(int i=1;i<=n;i++){        for(int j=0;j<=k;j++)            dis[i][j]=INF;        dis[i][0]=Dis[i];        b[i]=false;    }    for(int j=1;j<=k;j++){//从小到大枚举j        dis[s][j]=0;q.push(s);b[s]=true;        while(!q.empty()){            int x=q.front();q.pop();b[x]=false;            for(int i=fir[x];i;i=nex[i].nex){                    if(dis[nex[i].to][j]>dis[x][j]+nex[i].k){                        dis[nex[i].to][j]=dis[x][j]+nex[i].k;                        if(!b[nex[i].to]){                            b[nex[i].to]=true;                            q.push(nex[i].to);                        }                    }                    if(dis[nex[i].to][j]>dis[x][j-1]+nex[i].k/2){                        dis[nex[i].to][j]=dis[x][j-1]+nex[i].k/2;                        if(!b[nex[i].to]){                            b[nex[i].to]=true;                            q.push(nex[i].to);                        }                }            }        }    }}inline void solve(){    spfa();    ans=INF;    for(int i=0;i<=k;i++)        ans=min(ans,dis[t][i]);    printf("%lld",ans);}main(){    n=read();m=read();k=read();    s=read();t=read();    for(int i=1;i<=m;i++){        x=read();y=read();z=read();        add(x,y,z);add(y,x,z);    }    if(spfa1()){        printf("baka");        return 0;    }//判断是否联通    if(k==0){        printf("%lld",Dis[t]);        return 0;    }//水分..    solve();return 0;}

读书

这里写图片描述
这里写图片描述

Meet-in-Middle…
考虑m为0的情况,则只要让体力消耗小于k即可
在MiM后对左右两段消耗体力值从小到大排序,定义两个指针i,j分别指向s1的开头和s2的结尾
固定i,从右到左枚举j直到合法,此时的j即为可统计的答案,下次查找只需将i右移一位,接着左移j即可

如果m不为0,怎么办?

采用类似的思想,不同的是按照能造成的伤害排序,伤害是否合法按照刚才那样处理就可以,对于统计体力在给定范围内的,开个权值树状数组统计一下就好(见代码)

#include<algorithm>#include<ctype.h>#include<cstdio>#define N 27using namespace std;inline int read(){    int x=0,f=1; char c;    do {c=getchar();if(c=='-') f=-1;} while(!isdigit(c));    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));    return x*f;}int n,m,k;long long ans=0;int top1,top2;int q[1000020];inline void add(int x,int k){    for(;x<=1000000;x=x+(x&-x))        q[x]+=k;}inline int Sum(int x){    int sum=0;    for(;x;x=x-(x&-x))        sum=sum+q[x];    return sum;}struct Round{    int p,def,atk,a,b,c;}a[N];struct Data{    int res,hp;    Data(int _=0,int __=0):res(_),hp(__){}}s1[600500],s2[600500];//res:消耗多少体力 hp:造成多少伤害void dfs(int x,int res,int hp){    if(x==(n>>1)+1){        s1[++top1]=Data(res,hp);        return;    }    dfs(x+1,res+a[x].p,hp+a[x].a);    dfs(x+1,res+a[x].p-a[x].def,hp+a[x].a-a[x].b);    dfs(x+1,res+a[x].p+a[x].atk,hp+a[x].a+a[x].c);    return;}//Meet-in-Middle leftvoid dfs1(int x,int res,int hp){    if(x==n+1){        s2[++top2]=Data(res,hp);        return;    }    dfs1(x+1,res+a[x].p,hp+a[x].a);    dfs1(x+1,res+a[x].p-a[x].def,hp+a[x].a-a[x].b);    dfs1(x+1,res+a[x].p+a[x].atk,hp+a[x].a+a[x].c);    return;}//Meet-in-Middle rightinline bool cmp(Data a,Data b){    return a.hp>b.hp;}inline void solve(){    dfs(1,0,0);    dfs1(n/2+1,0,0);    sort(s1+1,s1+top1+1,cmp);    sort(s2+1,s2+top2+1,cmp);//这次按造成伤害值从小到大排序    int j=top2;    for(int i=1;i<=j;i++) add(s2[i].res,1);    for(int i=1;i<=top1;i++) {        while(s2[j].hp+s1[i].hp<m && j) {add(s2[j].res,-1);j--;}//让造成伤害值始终大于m        if(k-s1[i].res<0) continue;        ans=ans+Sum(k-s1[i].res);//统计此时满足体力限定的方案个数    }    printf("%lld",ans);    return;}inline void init();int main(){    init();    solve();    return 0;}inline void init(){//读入...    n=read();m=read();k=read();    for(int i=1;i<=n;i++)a[i].p=read();    for(int i=1;i<=n;i++)a[i].a=read();    for(int i=1;i<=n;i++)a[i].def=read();    for(int i=1;i<=n;i++)a[i].b=read();    for(int i=1;i<=n;i++)a[i].atk=read();    for(int i=1;i<=n;i++)a[i].c=read();}

A组:

Return

题目描述
他曾经将此作为一种高贵的气质、只留下潇洒的背影,直到他品尝了孤独的滋味、听到黑暗的夜里一个人默默的心跳。他向那个背影追去,却发现又回到原点。
现实中他依然在奔跑,他越跑越快,知道回到最初的时间,于是他又重新开始。然而轮回中、他早已死去,只有在梦魇中他才有一丝气息。
奔跑中的每一秒他都有一个速度,在现实中当然是越来越快的,直到回到最初的速度;在梦里,他同样在奔跑,不过梦,终究只是现实的闪回罢了,逃脱不了无尽的命运。现在你知道他在梦里每一秒的速度,梦里的一秒、即为现实中的一秒。请你统计一下梦里有多少秒在现实中满足 (现实中的上一秒的速度+这一秒的速度)mod(231 -1)=现实中的下一秒的速度。
这是一个长长的梦,所以现实中的每一秒都会在梦里出现的,不必担心会有断裂的时空存在。
输入描述
多组数据。
每组数据第一行一个整数 n,表示梦的长度。
第二行有 n 个整数,第 i 个整数表示梦中第 i 秒他的速度,保证在[0,231 ).
输出描述
对于第 i 组数据输出一行 Case #i: answer;如果现实只有一秒,他以恒定的速度在宇宙中茕茕而行,就像生活那样单调,就像清水一样淡,那么输出-1.
输入样例
3
1 2 3
5
1 2 3 5 7
6
2 3 1 2 7 5
输出样例
Case #1: 1
Case #2: 2
Case #3: 3
数据范围
对于%100 的数据,保证数据组数≤10.
对于%10 的数据,有 n=1.
对于%30 的数据,有 n≤3
对于%60 的数据,有 n≤1000
对于%100 的数据,有 n≤10000

样例3的解释:

现实中的速度是…5 7 1 2 3 5 7 1 2 3 5 7 1 2…

所以在梦里第一秒的速度是2,那么它在现实中前一秒是1,后一秒是3,所以1+2=3,是符合条件的。

梦中第二秒是3,2+3=5,get!

梦中第三秒是1,7+1≠2.

第四秒是2,1+2=3.

第五秒是7,5+7≠1.

第六秒是5,3+5≠7

所以答案就是3啦~


语文题…读懂之后才发现特别水…
sort+unique就行了…
对了-1还要特判一下

#include<algorithm>#include<ctype.h>#include<cstdio>#define N 10050#define int long long#define MOD 2147483647using namespace std;inline int read(){    int x=0,f=1;char c;    do {c=getchar();if(c=='-') f=-1;} while(!isdigit(c));    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));    return x*f;}int n,top,pre,ans,cnt,p,x;int a[N],b[N];main(){    while(scanf("%lld",&n)!=EOF){        ans=0ll;        for(int i=1;i<=n;i++) b[i]=a[i]=read();        sort(b+1,b+n+1);        top=unique(b+1,b+n+1)-b-1;        if(top==1){            printf("Case #%lld: %d\n",++p,-1);            continue;        }//特判无解        b[0]=b[top];b[top+1]=b[1];        for(int i=1;i<=n;i++){            x=lower_bound(b+1,b+top+1,a[i])-b;            if((b[x-1]+a[i])%MOD==b[x+1]) ans++;        }        printf("Case #%lld: %lld\n",++p,ans);    }return 0;}

One

题目描述
终于都走了。
曾经有 n-1 个人在他身边,然而现在只剩他一个人。
Who are you?Who am I?Why am I here?
走的越来越慢,人越来越少,可终于还是只剩一个了呢。
他们围成一圈,随机了一个人作为 1 号,然后逆时针依次编号。1号开始报数,报到 1,他走了;然后 2 号开始报数,2 号报了 1,3 号报了 2,于是 3 号也走了……每一轮都从上一次出局的下一个人开始报数,第 i 轮从 1 报到 i,报 i 的人出局。
直到只剩他一个人。却早已不记得他自己是谁。
他想知道他最初的号码,那上面承载着最初的记忆和最原始的愿望。
输入描述
第一行一个数 T 表示数据组数。
接下来 T 行,每行一个整数 n。
输出描述
共 T 行,每行一个数表示他原本的编号。
输入样例
2
2
3
输出样例
2
2
数据范围
对于%100 的数据,T≤10
对于%10 的数据,n≤5
对于%30 的数据,n≤3000
对于%60 的数据,n≤10000
对于%100 的数据,n≤10^7

约瑟夫问题
要事先了解一下如何线性推约瑟夫

最后得出的就是F(i)=(F(i-1)+M)%i,F(i)代表报i次数剩下的人是谁,M是每多少个人走一个

不同的是M是变化的,特殊处理一下就可以

关于公式怎么推的,请戳这里

#include<ctype.h>#include<cstdio>using namespace std;inline int read(){    int x=0,f=1;char c;    do {c=getchar();if(c=='-') f=-1;} while(!isdigit(c));    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));    return x*f;}int n,x,T;int main(){    T=read();    while(T--){        n=read();        x=0;        for(int i=2;i<=n;i++) x=(n-i+1+x)%i;        printf("%d\n",x+1);    }return 0;}

Phi

这里写图片描述
这里写图片描述

数论题,事实上就是个爆搜..

ans=pkiipki+1i+1....pkjj,还给出x=Πipki1i(pi1),我们只要枚举pi和相应的ki来想方设法拼出一个ans就可以了..

注意大质数的情况

#include<iostream>#include<cstdlib>#include<cstdio>#include<cmath>#define N 100005#define int long longusing namespace std;int n,m,cnt,pri[N];bool b[N];long long ans;bool check(int x){    int sz=(int)sqrt(x);    for(int i=1;pri[i]<=sz;i++) if(!(x%pri[i])) return 0;    return 1;}void dfs(int k,int now,long long sum){    if(sum>=ans) return;    if(now==1){ans=sum;return;}    if(now>m && check(now+1)) ans=min(ans,sum*(now+1));    for(int i=k+1;pri[i]-1<=m;i++){        if(pri[i]-1>now) break;        if(!(now%(pri[i]-1))){            int x=now/(pri[i]-1);            long long y=sum*pri[i];            dfs(i,x,y);            while(!(x%pri[i])){                x/=pri[i]; y*=pri[i];                dfs(i,x,y);            }        }    }}main(){    scanf("%d",&n);m=(int)sqrt(n);    if(n==1){        printf("1");        return 0;    }    for(int i=2;i<=50000;i++){        if(!b[i])pri[++cnt]=i;        for(int j=1;j<=cnt&&i*pri[j]<=50000;j++){            b[i*pri[j]]=true;            if(!(i%pri[j])) break;        }    }    ans=2147483648ll;    dfs(1,n,1);    if(ans<=2147483647) printf("%lld",ans);    else printf("-1");return 0;}