The 36th ACM/ICPC Asia Regional Shanghai Site —— Online Contest(HDU4021-4030)

HDU4022:Bombing

题意:二维坐标轴上有N个目标物,M次射击,有两种射击方式,一种是将X = a上的点都打掉,一种是将Y=a上的点都打掉,问一共能打掉多少个点?

思路:STL 的map<int, multiset<int> >即可搞定

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
using namespace std;
const int maxn = 100000+10;
int n,m;
map<int,multiset<int> > XX;
map<int,multiset<int> > YY;
void init(){
    XX.clear();
    YY.clear();
}
int main(){

    while(~scanf("%d%d",&n,&m) && n+m){
        init();
        int a,b;
        for(int i = 0; i < n; i++){
            scanf("%d%d",&a,&b);
            XX[a].insert(b);
            YY[b].insert(a);
        }
        for(int i = 0; i < m; i++){
            int ret;
            scanf("%d%d",&a,&b);
            if(a==0){
                ret = XX[b].size();
                for(multiset<int>::iterator it = XX[b].begin(); it != XX[b].end(); it++){
                    YY[*it].erase(b);
                }
                XX[b].clear();
            }else{
                ret = YY[b].size();
                for(multiset<int>::iterator it = YY[b].begin(); it != YY[b].end(); it++){
                    XX[*it].erase(b);
                }
                YY[b].clear();
            }
            printf("%d\n",ret);
        }
        printf("\n");


    }


    return 0;
}

HDU4024:Dwarven Sniper’s hunting

看清题意即可。。水的二分。

<pre name="code" class="cpp">#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const double eps = 1e-7;
double X1,Y1,X2,Y2,lx,ly,vd,vb,L;
double getDist(double x1,double y1,double x2,double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
bool can(double allt){
    double nx = X1+lx*allt,ny = Y1+ly*allt;
    double disT = getDist(X2,Y2,nx,ny);//圆心距
    double bullt = L/vb;//子弹的飞行时间
    double distH = (allt-bullt)*vd;//猎人走的时间
    if(distH+L-disT>-eps&&disT-L+distH>-eps) return true;
    else return false;
    //if(allt-(disT-L)/vd-bullt>-eps) return true;
   // else return false;
}
int main(){

    while(~scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2,&lx,&ly,&vd,&vb,&L)){
        if(X1<eps&&Y1<eps&&X2<eps&&Y2<eps&&lx<eps&&ly<eps&&vd<eps&&vb<eps&&L<eps) break;
        double l = 0,r = 1e9;
        while(r-l>eps){
            double mid = (l+r)/2;
            if(can(mid)){
                r = mid;
            }else{
                l = mid;
            }
        }
        printf("%.3f %.3f\n",L,l);
       // cout<<l<<endl;

    }
    return 0;
}


 HDU4026:Unlock the Cell Phone 

题意:求手机解锁图案的方案数。

思路:DP[mask][x][y]   每次划得时候注意中间不能有没按过的点和无用点。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
ll dp[1<<16][6][6];
int vis[1<<16][6][6];
int mat[6][6];
int gcdt[6][6];
int n,m,mark,dn,fmask;
vector<int>dots;
int idx[30];

int gcd(int a,int b){
    if(b==0) return a;
    else return gcd(b,a%b);
}
inline int ABS(int x){
    return x<0?-x:x;
}
ll  dfs(int mask,int x,int y){
    if(mask==fmask) return 1;
    if(vis[mask][x][y]== mark){
        return dp[mask][x][y];
    }
    vis[mask][x][y] = mark;
    ll ans = 0;
    for(int i = 0; i < dn; i++){
        int tx = dots[i]/m, ty = dots[i]%m;
        if(!(mask&(1<<i))){
            int g,dx,dy;
            if(ty==y){
                dx = (tx-x)/ABS(tx-x);
                dy = 0;
                g = ABS(tx-x);
            }
            else if(tx==x){
                dx = 0;
                dy = (ty-y)/ABS(ty-y);
                g =  ABS(ty-y);
            }
            else{
                g = gcdt[ABS(ty-y)][ABS(tx-x)];
                dx = (tx-x)/g;
                dy = (ty-y)/g;
            }
            bool flag = true;
            int tm = mask|(1<<i);
            for(int k = 1; k < g; k++){
                int nx = x+k*dx, ny = y+k*dy;
                if(mat[nx][ny]==1){
                    flag = false;
                    break;
                }
                else if (mat[nx][ny]==0){
                    int id = idx[nx*m+ny];
                    if(!(mask&(1<<id))) {
                        flag = false;
                        break;
                    }
                }
            }
            if(flag)   ans += dfs(tm,tx,ty);
        }
    }
    return dp[mask][x][y] = ans;
}
int main(){

    for(int i = 1; i <= 5; i++){
        for(int j = 1; j <= 5; j++){
            gcdt[i][j] = gcd(i,j);
        }
    }
    mark = 1;
    memset(vis,0,sizeof vis);
    while(~scanf("%d%d",&n,&m)){
        dots.clear();
        int cnt = 0;

        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                scanf("%d",&mat[i][j]);
                if(mat[i][j] == 0){
                    idx[i*m+j] = cnt++;
                    dots.push_back(i*m+j);
                }
            }
        }
        dn = dots.size();
        fmask = (1<<dn)-1;
        ll ans = 0;
        for(int i = 0; i < dn; i++){
            ans += dfs(1<<i,dots[i]/m,dots[i]%m);
        }
        printf("%I64d\n",ans);
        mark++;
    }
    return 0;
}

HDU4027:Can you answer these queries?

题意:N个数(N<=1e5),M次操作(M<=1e5) 有两种操作,一种是查询[x,y]的和,还有一种是修改[x,y]的每个数,使其变为自身的根号。

思路:不难看出,一个数最多被更新63次,多余的更新其实是无效的。因此更新的时候只要判断该区间的和等于区间长度的时候就不用更新。线段树就可搞定

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const double eps = 1e-7;
const int maxn = 100000+10;
typedef long long ll;
ll num[maxn];
int n,m;
struct node{
    int lson,rson;
    ll sum;
    int mid(){
        return (lson+rson)>>1;
    }
}tree[maxn*4];
void pushUP(int rt){
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
void build(int L,int R,int rt){
    tree[rt].lson = L;
    tree[rt].rson = R;
    if(L==R){
        tree[rt].sum = num[L];
        return;
    }
    int mid = tree[rt].mid();
    build(L,mid,rt<<1);
    build(mid+1,R,rt<<1|1);
    pushUP(rt);
}
ll query(int L,int R,int rt){
    if(L <= tree[rt].lson && R >= tree[rt].rson){
        return tree[rt].sum;
    }
    int mid = tree[rt].mid();
    ll ret = 0;
    if(L<=mid){
        ret += query(L,R,rt<<1);
    }
    if(R>mid){
        ret += query(L,R,rt<<1|1);
    }
    return ret;
}
void update(int L,int R,int rt){
    //cout<<L<<" "<<R<<endl;
    if(tree[rt].sum == tree[rt].rson-tree[rt].lson+1) return;
    if(tree[rt].rson == tree[rt].lson){
        tree[rt].sum = ll(sqrt(tree[rt].sum*1.0));
      //  cout<<tree[rt].sum<<endl;
        return;
    }
    int mid = tree[rt].mid();
    if(L <= mid){
        update(L,R,rt<<1);
    }
    if(R > mid){
        update(L,R,rt<<1|1);
    }
    pushUP(rt);
}
int main(){
    int T = 1;
    while(~scanf("%d",&n)){
        for(int i = 0; i < n; i++){
            scanf("%I64d",&num[i]);
        }
        scanf("%d",&m);
        build(0,n-1,1);
        printf("Case #%d:\n",T++);
        while(m--){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(b > c) swap(b,c);
            if(a==0){
                update(b-1,c-1,1);
            }else{
                printf("%I64d\n",query(b-1,c-1,1));
            }
        }
        printf("\n");        
    }
    return 0;
}



 
 


HDU4028:The time of a day

题意:从1~N(N<=40)这N个数中随意选取任意个数,求最小公倍数大于M的方案数。

思路:观察1~40这40个数的LCM, 最大为  2^5 * 3^3 * 5^2 * 7^1......不会超过long long,而且LCM 最多为  6*4*3*2*2*2。。。大约才3W多个。

考虑离散化。map<long long,long long> dp[i] 为  前i个数,最大公约数为X的方案数

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 40+10;
map<ll,ll>dp[maxn];
int n;
ll m;
ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
void init(){
    for(int i = 1; i <= 40; i++) dp[i].clear();
    for(int i = 1; i <= 40; i++) dp[i][i] = 1;
    for(int i = 2; i <= 40; i++){
        for(map<ll,ll>::iterator it = dp[i-1].begin(); it != dp[i-1].end(); it++){
            ll a = it->first,b = it->second;
            ll c = lcm(a,i);
            dp[i][a] += b;
            dp[i][c] += b;
        }
    }
}
int main(){
    int ncase,T=1;
    init();
    cin >> ncase;
    while(ncase--){
        scanf("%I64d%I64d",&n,&m);
        ll ans = 0;
        map<ll,ll>::iterator sta = dp[n].lower_bound(m);
        for(map<ll,ll>::iterator it = sta; it != dp[n].end(); it++){
            if(it->first >= m) ans += dp[n][it->first];
        }
        printf("Case #%d: %I64d\n",T++,ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值