2014上海全国邀请赛 【(5+3)/10】

33 篇文章 0 订阅

日常血崩。
菜到爆了.

A HDU 5090 Game with Pearls

——————————————————————————————————————————
给你一个序列,可以把每个元素加上k的倍数或者不加, 问你最后能不能组成一个序列,第1个元素是1,第2个元素是2,第3个元素是3,。。


暴力模拟就行,从大小1的数开始,留下本身需要的1个,剩下的不断加K,知道当前的数没出现过。

最后扫一下判断就行


#include <bits/stdc++.h>

using namespace std;

typedef long long int LL;

const int N = 1e5+7;

/******************************************************/

int a[N];
int vis[N];
int n,k;
int main(){
    int _;
    scanf("%d",&_);
    while(_--){
        memset(vis,0,sizeof(vis));
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            vis[a[i]]++;
        }
        int flag = 1;
        for(int i=1;i<=n;i++){
            for(int j=1;vis[i]>1;j++){
                if(vis[j*k+i] == 0){
                    vis[j*k+i] = 1;
                    vis[i]--;
                }
            }
        }

        for(int i=1;i<=n;i++){
            if(vis[i]!=1){
                flag=0;
                break;
            }
        }

        if(flag) puts("Jerry");
        else     puts("Tom");
    }
    return 0;
}

B HDU 5091 Beam Cannon

——————————————————————————————————————————
在二维坐标系上给你一堆点,然后问你w*h这么大的矩形,最多能包含多少个点


用到了扫描线;

首先考虑一维的情况
如果是一维的,要统计长为w的线段最多能包括多少个位置怎么搞?

可以反过来考虑,然后变成一堆长w的线段覆盖,然后求的就是那个被覆盖最多的点,区间更新后求最大值就行了

而这个题
可以考虑将一个点变成一个矩形,
然后从左向右扫描

使扫描过程中,遇到矩形的左边就+1,右边就-1,

并维护一个线段树区间更新取最大值就好了


#include <bits/stdc++.h>
typedef long long int LL;
using namespace std;

const int N   = 1e6+7;
const int MOD = 1e9+7;

#define mp make_pair
#define pb push_back
#define yy1 second.first
#define yy2 second.second
#define vv  first.second
/*********************************************/

vector<pair<pair<int,int>,pair<int,int> > >line;


int mx[N<<2],lazy[N<<2];

void pushdown(int rt){
    if(lazy[rt]){
        lazy[rt<<1  ]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        mx[rt<<1  ]+=lazy[rt];
        mx[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
}

void pushup(int rt){
    mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}

void update(int rt,int l,int r,int L,int R,int v){
    if(L<=l&&r<=R){
        lazy[rt]+=v;
        mx[rt]+=v;
        return ;
    }
    int m = r+l >> 1;
    pushdown(rt);
    if(L<=m) update(rt<<1  ,l  ,m,L,R,v);
    if(R> m) update(rt<<1|1,m+1,r,L,R,v);
    pushup(rt);
}

int query(int rt,int l,int r,int L,int R){

}
int n,w,h;
int main(){
    int _ = 1;
    for(;scanf("%d",&n);){
        if(n==-1) break;
        scanf("%d%d",&w,&h);

        memset(mx,0,sizeof(mx));
        memset(lazy,0,sizeof(lazy));
        line.clear();
        for(int i=1,x,y;i<=n;i++){
            scanf("%d%d",&x,&y);
            line.pb(mp(mp(x  , 1),mp(y,y+h)));
            line.pb(mp(mp(x+w, 2),mp(y,y+h)));
        }

        sort(line.begin(),line.end());

        int X = 90000;
        int ans = 0;
        for(int i=0;i<line.size();i++){
            if(line[i].vv == 1){
                update(1,1,X,line[i].yy1+20001,line[i].yy2+20001, 1);
                ans = max(ans,mx[1]);
            }
            else {
                ans = max(ans,mx[1]);
                update(1,1,X,line[i].yy1+20001,line[i].yy2+20001,-1);
            }

        }
        printf("%d\n",ans);
    }
    return 0;
}

C HDU 5092 Seam Carving

——————————————————————————————————————————
给你一个矩阵,让你找一个从上到下的路线,使得这个路线经过数的和最小,并且尽量靠右.

注意 a[i][j] 只能走到 a[i+1][j-1],a[i+1][j],a[i+1][j+1]


所以我们知道dp下到每个点的最小和,然后在最后一行找到最后一个最小的位置不算向回找就好了

#include <bits/stdc++.h>
typedef long long int LL;
using namespace std;

const int N   = 1e6+7;
const int MOD = 1e9+7;

/*********************************************/

LL dp[111][111],a[111][111];
int ms[111],len,n,m;
int main(){
    int _ = 1,kcase = 0;
    for(scanf("%d",&_);_--;){
        scanf("%d%d",&n,&m);

        len = 0;
        memset(dp,0,sizeof(dp));

        for(int i=1;i<=n;i++){
             a[i][0]= a[i][m+1]=10000000000000ll;
            dp[i][0]=dp[i][m+1]=10000000000000ll;
            for(int j=1;j<=m;j++)
                scanf("%lld",&a[i][j]);
        }

        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                dp[i][j]=a[i][j]+
                min(dp[i-1][j-1],min(dp[i-1][j],dp[i-1][j+1]));
            }
        }

        int p,mi = 10000000000000ll;;
        for(int i=1;i<=m;i++){
            if(dp[n][i]<=mi){
                mi = dp[n][i];
                p  = i;
            }
        }

        ms[++len] = p;
        int tp;
        for(int i=n-1;i;i--){
            mi = dp[i][p-1];
            tp = p-1;
            if(mi>=dp[i][p]){
                mi = dp[i][p];
                tp = p;
            }
            if(mi>=dp[i][p+1]){
                mi = dp[i][p+1];
                tp = p+1;
            }
            p=tp;
            ms[++len]=p;
        }

        printf("Case %d\n",++kcase);
        for(int i=len;i;i--)
            printf("%d%c",ms[i],(i==1)?'\n':' ');
    }
    return 0;
}

D HDU 5093 Battle ships

——————————————————————————————————————————
给你一个N*M的图,其中’*’可以放传,但是注意同一行一列只能放一个船,除非被’#’隔开,问你最多能放几个船.


首先考虑每个行和列分开之后,没有被隔开的部分就是一个整体了,

然后考虑 ,处理完的这一个个, 行与列没有被隔开的中

假设行1 和列1,列2,列3, 没有被隔开,

那么行1只能找一个列对应的位置来放船,

然后这就是一个二分匹配模型了,、、

然后就用行与列建二分图求最大匹配就好了

#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int>mp[25000+50];
int vis[25000+50];
int match[25000+50];
int find(int u){
  //  printf("%d %d\n",u,mp[u].size());
    for(int i=0;i<mp[u].size();i++){
        int v=mp[u][i];
        if(vis[v]==0){
            vis[v]=1;
            if(match[v]==-1||find(match[v])){
                match[v]=u;
                return 1;
            }
        }
    }
    return 0;
}

int h[111][111],l[111][111];
char a[111][111];

int n,m;

void add(int u,int v){
  //  printf("%d %d< -\n",u,v);
    mp[u].push_back(v);
}

void solve(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%s",a[i]+1);

    int cnt = 0;
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
        h[i][j]=l[i][j]=-1;

    memset(h,-1,sizeof(h));
    memset(l,-1,sizeof(l));

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]=='#') continue;
            if(-1==h[i][j-1])h[i][j]=++cnt;
            else h[i][j]=h[i][j-1];
        }
    }

    for(int j=1;j<=m;j++){
        for(int i=1;i<=n;i++){
            if(a[i][j]=='#') continue;
            if(-1==l[i-1][j])l[i][j]=++cnt;
            else l[i][j]=l[i-1][j];
        }
    }

    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
        if(a[i][j]=='*') add(h[i][j],l[i][j]);

    for(int i=1;i<=cnt;i++) match[i]=-1;

    int output=0;
    for(int i=1;i<=cnt;i++){
        for(int j=1;j<=cnt;j++) vis[j]=0;
        if(find(i))output++;
    }

    printf("%d\n",output);
    for(int i=1;i<=cnt;i++) mp[i].clear();
    return ;
}

int main(){
    int t;for(scanf("%d",&t);t--;) solve();
}

E HDU 5094 Maze

——————————————————————————————————————————
给你一个图,


二进制枚举状态搜索,

队友A的,待补

———————–Update—————————–

就是搜索么。
我用a[x][y][0~3] 记录每个位置4个方向的们需要那种钥匙开 用a[x][y][4]记录(x,y)这个位置的钥匙是那种,

因为又9种钥匙, 所以只要用一个9位的二进制数进行枚举就好了

用vis[x][y][1<<10] 来标记每种状态下走到(x,y)、、

然后直接搜索就好了

注意不能走到输出-1;

#include <bits/stdc++.h>

typedef long long int LL;
using namespace std;

#define abs(x) ((x)>0?(x):-(x))
#define rep(a,b,c) for(int a=(b),end=(c);a<=end;a++)

const int N   = 2000+7;
const int MOD = 1e9+7;

/******************************************************/

int n,m,q,k;
int a[55][55][10];
bool vis[55][55][1<<11];
int fx[]={0,0,1,-1};
int fy[]={1,-1,0,0};

struct node {
    int x,y,step,s;
};

int bfs(int x,int y){
    queue<node>q;
    node tmp,tem;
    tmp.x    = x,tmp.y = y;
    tmp.step = 0,tmp.s = 0;
    q.push(tmp);
    vis[1][1][0]=1;
    int xx,yy,ss,st;
    while(!q.empty()){
        tem = q.front();q.pop();
        if(tem.x == n&&tem.y == m)
            return tem.step;

        for(int i=0;i<4;i++){
            if( a[tem.x][tem.y][i]==-1) continue;
            if((a[tem.x][tem.y][i]&tem.s) != a[tem.x][tem.y][i]) continue;
            xx = tem.x + fx[i];
            yy = tem.y + fy[i];
            ss = (tem.s | a[xx][yy][4]);
            st = tem.step + 1;
            if(xx<1||xx>n) continue;
            if(yy<1||yy>m) continue;
            if(vis[xx][yy][ss]) continue;
            vis[xx][yy][ss]=1;
            tmp.x    = xx;
            tmp.y    = yy;
            tmp.s    = ss;
            tmp.step = st;
            q.push(tmp);
        }
    }
    return -1;
}


int main(){
    while(~scanf("%d%d%d",&n,&m,&q)){
        memset(vis,0,sizeof(vis));
        memset(a  ,0,sizeof(a  ));

        scanf("%d",&k);
        for(int i=1,f,x1,x2,y1,y2,p;i<=k;i++){
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&p);
            if(p == 0) f=-1;
            else       f=1<<(p-1);
            for(int j=0;j<4;j++){
                if(x1+fx[j]==x2&&y1+fy[j]==y2){
                    a[x1][y1][j]|=f;
                    break;
                }
            }
            for(int j=0;j<4;j++){
                if(x2+fx[j]==x1&&y2+fy[j]==y1){
                    a[x2][y2][j]|=f;
                    break;
                }
            }
        }

        scanf("%d",&k);
        for(int i=1,x1,y1,p;i<=k;i++){
            scanf("%d%d%d",&x1,&y1,&p);
            a[x1][y1][4]|=1<<(p-1);
        }

        printf("%d\n",bfs(1,1));
    }
    return 0;
}

F HDU 5095 Linearization of the kernel functions in SVM

——————————————————————————————————————————
给你10个系数,让你把10项的多项式的最简形式表示出来,


小模拟

注意开始的数是正数的时候没有正号,
系数为1 的要省略

#include <bits/stdc++.h>

using namespace std;

typedef long long int LL;

const int N = 1e5+7;

/******************************************************/

int a[N];
char ch[100]={' ','p','q','r','u','v','w','x','y','z'};
int n,k;
int main(){
    int _; scanf("%d",&_);
    while(_--){
        for(int i=1;i<=10;i++) scanf("%d",&a[i]);

        int i;
        for(i=1;i<=10;i++) if(a[i]!=0) break;

        int flag=0;

        for(;i<10;i++){
            if(a[i]==0) continue;
            if(a[i]<0) {flag=1;
                if(a[i]==-1) printf("-%c",ch[i]);
                else         printf("%d%c",a[i],ch[i]);
            }
            else {
                if(flag) printf("+");flag=1;
                if(a[i]!=1) printf("%d%c",a[i],ch[i]);
                else        printf("%c",ch[i]);
            }
        }

        if(a[10]!=0) {
            if(a[10]>0) {
                if(flag) printf("+");flag=1;
                printf("%d",a[10]);
            }
            else {
                printf("%d",a[10]),flag=1;
            }
        }
        if(flag == 0) printf("0");
        puts("");

    }
    return 0;
}
/***
5555
0 0 0 0 0 0 0 0 0 0
-5 -2  5 5 5 5 5 5 5 5
0 46 3 4 -5 -22 -8 -32 24 27
2 31 -5 0 0 12 0 0 -49 12
-1 -1 -1 0 0 4 0 0 -6 7
0 0 0 0 0 -5 0 0 0 0
1 1 1 1 1 1 1 1 1 1
-1 -1 -1 -1 -1 -1 -1 -1 -1
-1 1 -1 1 -1 1 -1 1 -1 1
1 -1 1 -1 1 -1 1 -1 1 -1

*/

G HDU 5096 ACM Rank

——————————————————————————————————————————

大模拟,不补.

H HDU 5097 Page Rank

——————————————————————————————————————————
待补…


I HDU 5098 Smart Software Installer

——————————————————————————————————————————
给你一堆程序,后面带’*’好的需要重启之后才能生效,’:’ 后面的是需要安装完这个程序,才能开始安装的程序

问你最少需要打印多少次


题目很水,就是题面太长了。没读。。。

只要注意到要把当前需要重启的程序个数最大化就好了。

过程就是个拓扑,

然后就是如何处理这个恶心的读入了。。。

#include <bits/stdc++.h>
typedef long long int LL;
using namespace std;

const int N   = 1e6+7;
const int MOD = 1e9+7;

#define pb push_back

/*********************************************/

int deg[N];
bool vis[N];
int cnt;
int ms[N],len;
int ms2[N],len2;

string s;char t[N];
vector<int >G[N];

void add(int u,int v){
    G[u].pb(v);
    deg[v]++;
}

map<string ,int >mp;

void topo(){
    queue<int >q;
    while(len) q.push(ms[len--]);

    while(!q.empty()){// puts("++");
        int u = q.front();q.pop();
//        printf("cnt = %d  : %d\n",cnt,u);
        for(int i=0;i<G[u].size();i++){
            int to = G[u][i];
            deg[to]--;
            if(deg[to] == 0){
                if(vis[to]) ms[++len] = to;
                else q.push(to);//,printf("%d <--\n",to);
            }
        }
    }
}

void solve(){
    len = len2 = 0;

    for(int i=1;i<=cnt;i++)
        if(deg[i]==0){
            if(vis[i]) ms2[++len2]=i;
            else        ms[++len ]=i;
        }
//    printf("<%d,%d>\n",len,len2);
    int ans = 0;
    for(;len||len2;){ans++;
        topo();
        while(len2) ms[++len] = ms2[len2--];
    }
    printf("%d\n",ans-1);

    for(int i=1;i<=cnt;i++) G[i].clear(),vis[i]=deg[i]=0;
    return ;
}

void init(){
    mp.clear();cnt=0;

    int flag;
    string id1,id2;
    while(getline(cin,s) != NULL){
         if(s[0] == '\0') break;
         istringstream sin(s);
         sin >> t;
         flag = 0;
         int len = strlen(t);
         for(int i = 0; i < len; ++i)
             if(t[i] == '*') flag = 1;
         t[len - 1 - flag] = '\0';
         id1 = t;
         if(mp[id1] == 0) mp[id1]= ++cnt;
         vis[mp[id1]] = flag;
         while(sin >> id2){
             if(mp[id2] == 0)
                 mp[id2] = ++cnt;
             add(mp[id2],mp[id1]);
         }
    }

    return ;
}

int main(){
    int _ = 1,kcase = 0;
    cin>>_;
    getchar();
    getchar();
    for(;_--;){
        init();
//        for(int i=1;i<=cnt;i++){
//            printf("%d: ",i);
//            for(int j=0;j<G[i].size();j++){
//                printf(" %d-%d*",G[i][j],deg[G[i][j]]);
//            }
//            puts("");
//        }
//        for(int i=1;i<=cnt;i++) printf("deg[%d]=%d\n",i,deg[i]);

        printf("Case %d: ",++kcase);
        solve();
    }
    return 0;
}

J HDU 5099 Comparison of Android versions

——————————————————————————————————————————

给你两个字符串,然后按照规则比较下大小.


我做傻逼了

队友A的

题傻逼不补

#include <bits/stdc++.h>
using namespace std;
char a[1500];
char b[1500];
#define mme(i,j) memset(i,j,sizeof(i))
void print(int vala ,int valb )
{
    if(vala>valb)printf(">");
    else if(vala==valb)printf("=");
    else printf("<");
}

int opt[3];
int main()
{
    int t;
    int kase=0;
    scanf("%d",&t);
    while(t--)
    {
        mme(opt,0);
        scanf("%s%s",a+1,b+1);
        printf("Case %d: ",++kase);
        if(a[1]==b[1])//0--->=   1---->  -1----<
            opt[1]=0;
        else if(a[1]>b[1])
            opt[1]=1;
        else opt[1]=-1;

        if(a[2]!=b[2])// bu tong
        {
            if(a[3]==b[3])
            {
                if(a[4]==b[4])
                {
                    if(a[5]==b[5])
                        opt[2]=0;
                    else{
                        if(a[5]>b[5])
                            opt[2]=1;
                        else
                            opt[2]=-1;
                    }
                }else {
                    if(a[4]>b[4])
                        opt[2]=1;
                    else opt[2]=-1;
                }
            }else {
                if(a[3]>b[3])
                    opt[2]=1;
                else
                    opt[2]=-1;
            }
        }else {
            if(strcmp(a+3,b+3)>0)
                opt[2]=1;
            else if(strcmp(a+3,b+3)<0)
                opt[2]=-1;
            else opt[2]=0;
        }
        if(opt[1]==1)
            printf("> ");
        else if(opt[1]==-1)
            printf("< ");
        else printf("= ");

        if(opt[2]==1)
            printf(">\n");
        else if(opt[2]==-1)
            printf("<\n");
        else printf("=\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值