Contest2288

                                        Problem A: gift

                                                                  Time Limit: 1000 ms   Memory Limit: 128 MB

Input

输入的第一行为一个整数t。 接下来t行,每行包含九个自然数a,b,c,d,e,f,g,h,i

Output

输出t行,每行一个整数,表示2^a+2^b+2^c+2^d+2^e+2^f+2^g+2^h+i。

Sample Input

1
21 30 0 0 0 0 0 0 2147483647

Sample Output

3223322629

HINT

40%   t<=1000

100%  t<=100000 a,b,c,d,e,f,g,h<=60 i<=9223372036854775808


看到数据范围后,觉得这根本不是礼物好吗?

刚开始觉得要用高精度,后来发现用unsigned long long再加上极限数据的特判就行了。

AC code:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
unsigned long long a[10],ans,mi[65],inf=9223372036854775808;
int t,s;
int x[100],y[100];
unsigned long long mix(unsigned long long n){//快速幂
    if(mi[n]!=0)return mi[n];
    if(n%2==0)return mi[n]=mix(n/2)*mix(n/2);
    else return mi[n]=mix(n/2)*mix(n/2+1);
}
int main(){
    scanf("%d",&t);
    mi[0]=1;
    mi[1]=2;
    while(t--){
        ans=0;
        for(int i=1;i<=9;i++){
        	scanf("%llu",&a[i]);
        	if(i!=9)s+=a[i];
		};
        if(s==60*8&&a[9]==inf){//特判
        	cout<<"18446744073709551616"<<endl;
        	continue;
	}
        for(int i=1;i<=8;i++){
            ans+=mix(a[i]);
        }
        ans+=a[9];
        printf("%llu\n",ans);
    }
    return 0;
}//测试数据
/*
1
60 60 60 60 60 60 60 60 9223372036854775808
*/
/*
1
60 58 59 59 58 60 58 58 1993031419930314
*/
/*
2
60 60 60 60 60 60 60 60 9223372036854775808
60 58 59 59 58 60 58 58 1993031419930314
*/

代码如果不太好看不要喷我哈~

                                    Problem B: 新数独

                                                                Time Limit: 1000 ms    Memory Limit: 128 MB

Description


Input

输入一共 15 行,包含一个新数独的实例。第奇数行包含左右方向的符号( < > ),第偶数行包含上下方向的符号( ^ v )。

Output

输出包含 9 行,每行 9 1~9 的数字,以单个空格隔开。输入保证解惟一。

Sample Input

< >   > <   > <

v v ^ ^ v v ^ ^ ^

 < <   > <   > <

^ ^ ^ v ^ ^ ^ v v

 < <   < <   > >

 > <   > >   > >

v ^ ^ ^ ^ v v v ^

 > >   > >   < >

v v ^ v ^ v ^ v ^

 > <   < >   > >

 < <   < <   > <

v ^ v v v v ^ ^ v

 < >   > <   < >

^ v v v ^ v ^ v v

 < >   < >   < >

Sample Output

4 9 1 7 3 6 5 2 8

2 3 7 8 1 5 6 4 9

5 6 8 2 4 9 7 3 1

9 1 3 6 5 4 8 7 2

8 5 4 9 7 2 1 6 3

7 2 6 3 8 1 9 5 4

3 4 9 5 6 8 2 1 7

1 8 5 4 2 7 3 9 6

6 7 2 1 9 3 4 8 5

哎,这题真的恶心了我好久,特别是输入。

其实记录好每行、每列、每个九宫格里数的关系,每个格子和它的上、左两个数之间的大小关系直接爆搜就好。

AC code:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int l[10][10],up[10][10],n[15][10],m[15][10],g[10][10];
int a[10][10];
void print(){//输出
    for(int i=1;i<=9;i++){
        for(int j=1;j<=9;j++){
            cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
}
int cmp(int x,int y){
    return x>y?-1:1;
}
bool check(int x,int y,int n){
    if(cmp(n,a[x-1][y])!=up[x][y]&&up[x][y]!=0)return 0;//比较上下
    if(cmp(n,a[x][y-1])!=l[x][y]&&l[x][y]!=0)return 0;//比较左右
    return 1;
}
void dfs(int x,int y){
    for(int i=1;i<=9;i++){//试数
        if(!n[x][i]&&!m[y][i]&&!g[(x-1)/3*3+(y-1)/3+1][i]&&check(x,y,i)){//n数组记录每行,m数组记录每列,g数组记录每个九宫格
            n[x][i]=g[(x-1)/3*3+(y-1)/3+1][i]=m[y][i]=1;
            a[x][y]=i;//记录
            if(x==9&&y==9){//只要一个解
                print();
                exit(0);//赶紧溜了
            }
            else (y==9?dfs(x+1,1):dfs(x,y+1));
            n[x][i]=g[(x-1)/3*3+(y-1)/3+1][i]=m[y][i]=0;
            a[x][y]=0;
        }
    }
}
int main(){
    char ch[2];
    for(int i=1;i<=9;i++){//恶心的输入
        for(int j=1;j<=9;j++){//l数组记录左右的大小关系,up数组记录上下的大小关系
            if(j%3!=0){
                scanf("%s",ch);
                if(ch[0]=='>')l[i][j+1]=1;
                else l[i][j+1]=-1;
            }
        }
        if(i%3!=0){
            for(int j=1;j<=9;j++){
                scanf("%s",ch);
                if(ch[0]=='v')up[i+1][j]=1;
                else up[i+1][j]=-1;
            }
        }
    }
    dfs(1,1);//爆搜开始了~
    return 0;
}
/*
< >   > <   > <
v v ^ ^ v v ^ ^ ^
 < <   > <   > <
^ ^ ^ v ^ ^ ^ v v
 < <   < <   > >
 > <   > >   > >
v ^ ^ ^ ^ v v v ^
 > >   > >   < >
v v ^ v ^ v ^ v ^
 > <   < >   > >
 < <   < <   > <
v ^ v v v v ^ ^ v
 < >   > <   < >
^ v v v ^ v ^ v v
 < >   < >   < >
*/

                                    Problem C: 城市交通

                                                                 Time Limit: 1000 ms   Memory Limit: 128 MB

Description

由于牛奶市场的需求,奶牛必须前往城市,但是唯一可用的交通工具是出租车.教会奶牛如何在城市里打的.

给出一个城市地图,东西街区E(1≤E≤40),南北街区N(1≤N≤30).制作一个开车指南给出租车司机,告诉他如何从起点(用S表示)到终点(用E表示).每一个条目用空格分成两部分,第一个部分是方向(N,E,S,W之一),第二个是一个整数,表示要沿着这个方向开几个十字路口.如果存在多条路线,你应该给出最短的.数据保证,最短的路径存在且唯一.地图中“+”表示十字路口,道路用“I”和“一”表示.建筑和其他设施用“.”表示.下面是一张地图:

出租车可以沿着东,北,西,北,东开两个十字路口,以此类推.具体将由样例给出。

Input

第1行:两个用空格隔开的整数N和E.

第2到2N行:每行有2E-I个字符,表示地图.

Output

每行有一个表示方向的字母和一个表示要开几个十字路口的数字表示.

Sample Input

3 6
+-+-+.+-+-+
|...|.....|
+-+.+-+-+-+
..|.......|
S-+-+-+.E-+

Sample Output

E 1
N 1
W 1
N 1
E 2
S 1
E 3
S 1
W 1

有人说这题用广搜好,我觉得吧......用SPFA更好些

把每个 + 看成一个点,每个 | 或 - 看成一条边,然后跑一遍最短路即可。

(代码有点长,思路很清晰的,耐心看一看哈,看不下去的别喷我)

AC code:

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
int n,m,head[4800],len,dis[4800],lu[4800],s,t;
char ans[4805];
bool vis[4800];
struct edge{//边结构体
    int v,next;//v表示指向点,next表示与这条边同一出发点的另一条边
    edge(){}
    edge(int _v,int _next){//构造函数
        v=_v;
        next=_next;
    }
}e[9600];
char map[100][100];
void init(){//初始化
    len=0;
    memset(head,-1,sizeof(head));
}
void spfa(int u){//啥,你不会spfa?那我也无能为力了
    memset(dis,0x3f,sizeof(dis));
    dis[u]=0;
    lu[u]=s;
    queue<int> q;
    q.push(u);
    while(!q.empty()){
        u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].v;
            if(dis[v]>dis[u]+1){
                dis[v]=dis[u]+1;
                lu[v]=u;
                if(!vis[v]){
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
}
int get(int x,int y){//get函数计算点的编号
    return (x-1)*m+y;
}
void add(int u,int v){//插入边
    e[len]=edge(v,head[u]);
    head[u]=len++;
}
int tot;
void find(int x){
    if(x==s)return;
    find(lu[x]);
    tot++;
    if(x==lu[x]+2)ans[tot]='E';
    if(x==lu[x]-2)ans[tot]='W';
    if(x==lu[x]+m*2)ans[tot]='S';
    if(x==lu[x]-m*2)ans[tot]='N';
}
int main(){
    init();
    cin>>n>>m;
    n=n*2-1;
    m=m*2-1;
    char ch;
    ch=getchar();
    for(int i=1;i<=n;i++){//输入,把S和E看成+
        for(int j=1;j<=m;j++){
            map[i][j]=getchar();
            if(map[i][j]=='S'){
                s=get(i,j);
                map[i][j]='+';
            }
            if(map[i][j]=='E'){
                t=get(i,j);
                map[i][j]='+';
            }
        }
        ch=getchar();
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(i>=3){//插入边
                if(map[i-2][j]=='+'&&map[i-1][j]!='.'){
                    add(get(i-2,j),get(i,j));
                    add(get(i,j),get(i-2,j));
                }
            }
            if(j>=3){//还是插入边
                if(map[i][j-2]=='+'&&map[i][j-1]!='.'){
                    add(get(i,j-2),get(i,j));
                    add(get(i,j),get(i,j-2));
                }
            }
        }
    }
    spfa(s);//不多说,直接spfa
    find(t);//找答案
    for(int i=1;i<=tot;i++){//输出
        int p=0;
        while(ans[i]==ans[i+1]){
            p++;
            i++;
        }
        printf("%c %d\n",ans[i],p+1);
    }
    return 0;
}//数据看上面↑↑↑

                                    Problem D: 雷涛的小猫

                                                                  Time Limit: 2000 ms   Memory Limit: 128 MB

Description

Input

Output

Sample Input

3 10 2
3 1 4 10
6 3 5 9 7 8 9
5 4 5 3 6 9

Sample Output

8

HINT

直接动规,不多说。状态转移方程:@#¥%……%   我太懒了不想写  聪明人才看得懂。(老铁没毛病)

AC code:

#include<iostream>
#include<cstdio>
using namespace std;
int n,h,d,a[2005][2005],f[2005][2005];
int main(){
    scanf("%d%d%d",&n,&h,&d);
    int x,y;
    for(int i=1;i<=n;i++){//倒序存储
        scanf("%d",&x);
        for(int j=1;j<=x;j++){
            scanf("%d",&y);
            a[i][h-y+1]++;
        }
    }
    for(int i=1;i<=n;i++){
        int sum=0;
        for(int j=1;j<=d;j++){//在h-d+1之上的位置只能从树顶跳下来
            sum+=a[i][j];
            f[i][j]=sum;
        }
    }
    for(int i=d+1;i<=h;i++){//注意一下i和j与上面表示的是不同的
        int maxn=0;
        for(int j=1;j<=n;j++)maxn=max(maxn,f[j][i-d]);
        for(int j=1;j<=n;j++)f[j][i]=max(maxn,f[j][i-1])+a[j][i];
    }
    int ans=0;
    for(int i=1;i<=n;i++)ans=max(ans,f[i][h]);
    cout<<ans;
    return 0;
}
呼,终于写完了,第一次写博客,大家多多支持下哈!

                                                                                                                                                           

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值