NCPC 2016:简单题解

A .Artwork

pro:给定N*M的白色格子,然后Q次黑棒,输出每次加黑棒后白色连通块的数量。(N,M<1e3, Q<1e4)

sol:倒着离线做,并查集即可。

(在线做法:https://www.cnblogs.com/asdfsag/p/10485607.html

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn = 1e6 + 10;
int a[1010][1010], fa[maxn], ID[1010][1010];
struct node
{
    int x1, y1, x2, y2;
    node(){}
    node(int x1, int y1, int x2, int y2):x1(x1), y1(y1), x2(x2), y2(y2){}
}c[maxn];
int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}
int dir[][2] = {1,0,0,1,-1,0,0,-1};
stack<int>s;
int main()
{
    int n, m, q, tot = 0, x1, y1, x2, y2;
    scanf("%d%d%d", &n, &m, &q);
    for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){ID[i][j] = ++tot; fa[tot] = tot;}
    for(int i = 1; i <= q; i++)
    {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        c[i] = node(x1, y1, x2, y2);
        for(int x = x1; x <= x2; x++)for(int y = y1; y <= y2; y++)a[x][y]++;
    }
    int white = 0, cnt = 0;
    for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)if(!a[i][j])
    {
        white++;
        for(int k = 0; k < 4; k++)
        {
            int x = i + dir[k][0], y = j + dir[k][1];
            if(x >= 1 && x <= n && y >= 1 && y <= m && !a[x][y])
            {
                int u = ID[i][j], v = ID[x][y];
                u = Find(u);v = Find(v);
                if(u != v)fa[u] = v, cnt++;
            }
        }
    }
    s.push(white - cnt);
    for(int i = q; i >= 2; i--)
    {
        for(int x = c[i].x1; x <= c[i].x2; x++)
            for(int y = c[i].y1; y <= c[i].y2; y++)
        {
            a[x][y]--;
            if(!a[x][y])
            {
                white++;
                for(int k = 0; k < 4; k++)
                {
                    int xx = x + dir[k][0], yy = y + dir[k][1];
                    if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && !a[xx][yy])
                    {
                        int u = ID[x][y], v = ID[xx][yy];
                        u = Find(u);v = Find(v);
                        if(u != v)fa[u] = v, cnt++;
                    }
                }
            }
        }
        s.push(white - cnt);
    }
    while(!s.empty()){cout<<s.top()<<endl;s.pop();}
    return 0;
}
View Code

C .Card Hand Sorting

pro:给定N张扑克牌,保证来自一副牌,有四种花色。现在让你重排,同种花色放一起,内部递增或者递减。 重排的方式是抽出一张牌,插入到某位置。

sol:四种花色,枚举花色的排列,再枚举每种花色内是递增还是递减。  对于每种方案,ans=N-LIS。

(写个结构体还是蛮方便的。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
map<char, int>level_num, level_color;
struct node
{
    char num, color;
    node(){}
    node(char num, char color):num(num), color(color){}
    bool operator <(const node& now)const
    {
        if(level_color[color] == level_color[now.color])//花色相同
        {
            //奇数递增,偶数递减
            if(level_color[color] & 1)return level_num[num] < level_num[now.num];
            else return level_num[num] > level_num[now.num];
        }
        return level_color[color] < level_color[now.color];
    }
    bool operator == (const node& now)const{return num == now.num && color == now.color;}
}a[110], b[110];
int dp[60][60], n;
int solve()
{
    memset(dp, 0, sizeof(dp));
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            if(a[i] == b[j])dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
        }
    }
    return n - dp[n][n];
}
char s[] = "shdc";
int c[5];
int main()
{
    int tot = 0;
    for(char i = '2'; i <= '9'; i++)level_num[i] = ++tot;
    level_num['T'] = ++tot;level_num['J'] = ++tot;level_num['Q'] = ++tot;
    level_num['K'] = ++tot;level_num['A'] = ++tot;
    cin >> n;
    for(int i = 1; i <= n; i++){cin >> a[i].num >> a[i].color;b[i] = a[i];}
    for(int i = 1; i <= 4; i++)c[i] = i;
    int ans = n;
    do
    {
        for(int i = 1; i <= 4; i++)level_color[s[i - 1]] = c[i];
        for(int i = 0; i < (1 << 4); i++)
        {
            for(int j = 0; j < 4; j++)
            {
                level_color[s[j]] *= 2;
                if(i & (1 << j))level_color[s[j]]++;
            }
            sort(b + 1, b + 1 + n);
            ans = min(ans, solve());
        }
    }while(next_permutation(c + 1, c + 5));
    cout<<ans<<endl;
    return 0;
}
View Code

D .Daydreaming Stockbroker

pro:开始你有100元,给出N天的股价单价,你每天可以选择用当时的价格交易。限制持有股份不超过100000, 问最后有多少钱。N<365;

sol:枚举之前哪天买即可。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=200010;
ll a[maxn],dp[maxn],ans=100;
int main()
{
    int N;
    scanf("%d",&N);
    rep(i,1,N) scanf("%lld",&a[i]);
    dp[1]=dp[2]=100;
    rep(i,2,N){
        rep(j,1,i-1){
           ll t=min(dp[j]/a[j],100000LL);
           dp[i]=max(t*a[i]+dp[j]-t*a[j],dp[i]);
        }
        ans=max(ans,dp[i]);
        dp[i+1]=max(dp[i+1],dp[i]);
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

E .Exponial

pro:给定N,M。求。N^((N-1)^(N-2)...)%M;(N,M<1e9)

sol:显然欧拉降幂。 注意幂>mod时才能降幂,4以内的小于1e9,所以特判。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,m;
int phi(int x){
    int ans=x;
    for(int i=2;i*i<=x;i++)
        if(x%i==0){
            ans/=i;ans*=i-1;
            while(x%i==0) x/=i;
    }
    //cout<<x<<" "<<ans<<" "<<endl;;
    if(x>1) ans/=x,ans*=x-1;
    return ans;
}
int ksm(int x,int y,int p){
    int ans=1;
    for(;y;y>>=1){
        if(y&1)ans=(ll)ans*x%p;
        x=(ll)x*x%p;
    }
    return ans;
}
int dfs(int x,int y){
    if(y==1) return 0;
    if(x==1) return 1;
    if(x==5) return ksm(x,262144,y);
    if(x==4) return ksm(x,9,y);
    if(x==3) return ksm(x,2,y);
    if(x==2) return x%y;

    int ph=phi(y);
    return ksm(x,dfs(x-1,ph)+ph,y);
}
int main(){
    scanf("%d%d",&n,&m);
    printf("%d",dfs(n,m));
    return 0;
}
View Code

G .Game Rank

排位模拟题。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,lev=25,st,wins;
char s[10010];
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++){
        if(s[i]=='W'){
            if(lev>=6&&wins>=2)st+=2,wins++;
            else st++,wins++;
            while(lev>20&&st>2)lev--,st-=2;
            while(lev>15&&st>3)lev--,st-=3;
            while(lev>10&&st>4)lev--,st-=4;
            while(st>5)lev--,st-=5;
        }
        else{
            wins=0;
            if(lev<=20)st--;
            if(st<0){
                lev++;
                if(lev>20)lev=20,st=0;
                else if(lev>15)st=2;
                else if(lev>10)st=3;
                else st=4;
            }
        }
        if(lev<=0)return 0*puts("Legend");
    }
    printf("%d",lev);
    return 0;
}
View Code

H .Highest Tower

pro:BZOJ4886

小Q正在玩一个叠塔的游戏,游戏的目标是叠出尽可能高的塔。在游戏中,一共有n张矩形卡片,其中第i张卡片的
长度为a_i,宽度为b_i。小Q需要把所有卡片按一定顺序叠成一座塔,要求对于任意一个矩形,它的长度要严格大
于它上边的任意一个矩形的长度。塔的高度为所有矩形的宽度之和。在游戏中,小Q可以将卡片翻转90度来使用,
而且必须用上全部n张卡片。请写一个程序,帮助计算小Q能叠出最高的塔的高度。

sol:定向问题。 不难证明最后是一棵或者多棵树或者环套树。 证明https://blog.csdn.net/V5ZSQ/article/details/79337446?utm_source=blogxgwz8

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=2000101;
map<int,int>mp;
int ind[maxn],tot,mx[maxn],fa[maxn],tag[maxn],val[maxn]; ll ans;
int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
int u[maxn],v[maxn];
int main()
{
    int N,x,y;
    scanf("%d",&N);
    rep(i,1,N){
        scanf("%d%d",&u[i],&v[i]);
        x=u[i]; y=v[i];
        if(!mp[x]) mp[x]=++tot,val[tot]=mx[tot]=x;
        if(!mp[y]) mp[y]=++tot,val[tot]=mx[tot]=y;
        x=u[i]=mp[x]; y=v[i]=mp[y];
        ind[x]++; ind[y]++;
    }
    rep(i,1,tot) fa[i]=i;
    rep(i,1,tot){
        x=find(u[i]); y=find(v[i]);
        if(tag[x]&&tag[y]) continue;
        if(x==y) tag[y]=1;
        else fa[x]=y,tag[y]|=tag[x],mx[y]=max(mx[x],mx[y]);
    }
    rep(i,1,tot){
        ans+=1LL*(ind[i]-1)*val[i];
        if(find(i)==i&&!tag[i]) ans+=mx[i];
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

J .Jumbled Compass

模拟。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=200010;
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<=180;i++){
        if((n+i)%360==m)return 0*printf("%d",i);
        if((n-i+360)%360==m)return 0*printf("%d",-i);
    }
}
View Code

K .Keeping the Dogs Apart

题意: 给定两支猫的行走路线, 都是直线行走, 求他们都在走的最近距离.

思路: 模拟即可. 每次得到min{到转折点的时间},  然后得到结束位置, 至于这个过程的最近距离,我们可以假设一个不动,那么就是点到线段的距离. 继续模拟.

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=200010;
double x[maxn][2],y[maxn][2],ans;
const double inf=1e200;
const double pi=4*atan(1.0);
struct point{
    double x,y;
    point(double a=0,double b=0):x(a),y(b){}
};
int dcmp(double x){ return fabs(x)<0.0000000000001?0:(x<0?-1:1);}
point operator +(point A,point B) { return point(A.x+B.x,A.y+B.y);}
point operator -(point A,point B) { return point(A.x-B.x,A.y-B.y);}
point operator *(point A,double p){ return point(A.x*p,A.y*p);}
point operator /(point A,double p){ return point(A.x/p,A.y/p);}
point rotate(point A,double rad){
    return point(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
bool operator ==(const point& a,const point& b) {
     return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double dot(point A,point B){ return A.x*B.x+A.y*B.y;}
double det(point A,point B){ return A.x*B.y-A.y*B.x;}
double dot(point O,point A,point B){ return dot(A-O,B-O);}
double det(point O,point A,point B){ return det(A-O,B-O);}
double length(point A){ return sqrt(dot(A,A));}
double angle(point A,point B){ return acos(dot(A,B)/length(A)/length(B));}
bool isPointOnSegment(point p,point a1,point a2)
{
    //点是否在线段上
    return dcmp(det(a1-p,a2-p)==0&&dcmp(dot(a1-p,a2-p))<=0);
}
double distoseg(point P,point A,point B)
{
    if(isPointOnSegment(P,A,B)) return 0.0;
    //点到线段距离
    if(A==B) return length(P-A);
    point v1=B-A,v2=P-A,v3=P-B;
    if(dcmp(dot(v1,v2))<0) return length(v2);
    else if(dcmp(dot(v1,v3))>0) return length(v3);
    return fabs(det(v1,v2)/length(v1));
}
double dist(double x1,double y1,double x2,double y2)
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void solve(int A,int B,double t)
{
    double dx[2],dy[2];
    double d1=dist(x[A][0],y[A][0],x[A+1][0],y[A+1][0]);
    double d2=dist(x[B][1],y[B][1],x[B+1][1],y[B+1][1]);
    dx[0]=(x[A+1][0]-x[A][0])/d1; dy[0]=(y[A+1][0]-y[A][0])/d1;
    dx[1]=(x[B+1][1]-x[B][1])/d2; dy[1]=(y[B+1][1]-y[B][1])/d2;
    double sx=x[A][0],sy=y[A][0],tx=x[A][0]+(dx[0]-dx[1])*t,ty=y[A][0]+(dy[0]-dy[1])*t;
    double res=distoseg(point(x[B][1],y[B][1]),point(sx,sy),point(tx,ty));
    ans=min(ans,res);
    x[A][0]+=dx[0]*t; y[A][0]+=dy[0]*t;
    x[B][1]+=dx[1]*t; y[B][1]+=dy[1]*t;
}
int main()
{
    int N,M;
    scanf("%d",&N);
    rep(i,1,N) scanf("%lf%lf",&x[i][0],&y[i][0]);
    scanf("%d",&M);
    rep(i,1,M) scanf("%lf%lf",&x[i][1],&y[i][1]);
    ans=110000000000;
    int A=1,B=1;
    while(A<N&&B<M){
        double da=dist(x[A][0],y[A][0],x[A+1][0],y[A+1][0]);
        double db=dist(x[B][1],y[B][1],x[B+1][1],y[B+1][1]);
        if(da<db){
            solve(A,B,da);
            A++;
        }
        else if(da==db){
            solve(A,B,da);
            A++; B++;
        }
        else {
            solve(A,B,db);
            B++;
        }
    }
    printf("%.8lf\n",ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/hua-dong/p/10656666.html
今日推荐