• Gym-101653:acific Northwest Regional Contest (2019训练第一场)


    本套题没有什么数据结构题,图论题,唯一有价值的就是Q题博弈,在最后面,读者可以直接拉到最下面。

    (还剩下两个,估计每什么价值的题,懒得补了

    M .Polyhedra

    pro:欧拉公式,V-E+F=2;给定V,E,求F

    sol:F=E-V+2;

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            printf("%d
    ", b - a + 2);
        }
        return 0;
    }
    View Code

    N .Majority

    pro:  给定一些一些1到1000的数字,问最小的出现次数最多的数字。

    sol:  模拟。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    int num[maxn];
    int main()
    {
         int T,N,x;
         scanf("%d",&T);
         while(T--){
            scanf("%d",&N);
            rep(i,1,1000) num[i]=0;
            rep(i,1,N){
                scanf("%d",&x);
                num[x]++;
            }
            int ans=0,x=-1;
            rep(i,1,1000) {
                if(num[i]>x) ans=i,x=num[i];
            }
            printf("%d
    ",ans);
         }
         return 0;
    }
    View Code

    O .Diamonds

    pro:给定一些二元组,求最长的序列,满足a递增,b递减。

    sol:N^2暴力即可。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    struct in{
        double x,y;
    }s[maxn];
    int dp[210];
    int main()
    {
         int T,N,ans;
         scanf("%d",&T);
         while(T--){
            scanf("%d",&N); ans=1;
            rep(i,1,N) scanf("%lf%lf",&s[i].x,&s[i].y);
            rep(i,1,N){
                dp[i]=1;
                rep(j,1,i-1){
                    if(s[j].x<s[i].x&&s[j].y>s[i].y) dp[i]=max(dp[i],dp[j]+1);
                }
                ans=max(ans,dp[i]);
            }
            printf("%d
    ",ans);
         }
         return 0;
    }
    View Code

    R .Ramp Number

    pro:一个数字X是合法的,当且仅当各位数字从左到右不降。 如果一个数字的合法,求多少个小于他的数是合法的。

    sol:基本数位DP。

    #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=100;
    ll dp[maxn][10]; char c[maxn]; int a[maxn],len;
    ll dfs(int pos,int lim,int now)
    {
        if(pos==len) return 1;
        if(!lim&&dp[pos][now]) return dp[pos][now];
        ll res=0; int up=9; if(lim) up=a[pos+1];
        rep(j,now,up) res+=dfs(pos+1,lim&&j==a[pos+1],j);
        return dp[pos][now]=res;
    }
    void solve()
    {
        ll res=0;
        rep(i,1,len){
            memset(dp,0,sizeof(dp));
            int up=9; if(i==1) up=a[1];
            rep(j,1,up) res+=dfs(i,i==1&&j==up,j);
        }
        printf("%lld
    ",res);
    }
    int main()
    {
         int T;
         scanf("%d",&T);
         while(T--){
            scanf("%s",c+1);
            len=strlen(c+1);
            rep(i,1,len) a[i]=c[i]-'0';
            bool F=true;
            rep(i,2,len) if(a[i]<a[i-1]) F=false;
            if(!F){ puts("-1"); continue;}
            solve();
         }
         return 0;
    }
    View Code

    X .Wrench

    pro:把一个带小数的数字表示为整数 加一个 分数形式,满足分母是2的幂次,而且要越小的满足的,允许有最后一位的误差。

    sol:模拟,细节需要注意。

    #include<bits/stdc++.h>
    using namespace std;
    int t,n;
    char s[1010],s1[100];
    int main(){
        for(scanf("%d",&t);t--;){
            scanf("%s",s);n=strlen(s);
            int p=0;bool flag=0,flag1=0;
            while(s[p]=='0'&&p<n)p++;
            while(s[p]!='.'&&p<n)putchar(s[p++]),flag1=1;
            for(int i=p+1;i<n;i++)
                if(s[i]!='0'){flag=1;break;}
            if(flag){if(flag1)putchar(' ');}
            else{puts(""");continue;}
            flag=0;
            for(int i=2;i<=128;i<<=1){
                for(int j=1;j<i;j++){
                    double x=1.0*j/i;
                    for(int v=0;v<8;v++)x*=10,s1[v]=(int)x%10+'0';
                    bool f=1;
                    for(int k=1;p+k<n;k++)
                        if(s1[k-1]!=s[p+k]&&(p+k<n-1||s1[k-1]+1!=s[p+k])){f=0;break;}
                    if(f){printf("%d/%d"
    ",j,i);flag=1;break;}
                }
                if(flag)break;
            }
        }
        return 0;
    }
    View Code

    U .Top 25

    题意:给定A和B,分别是不同的1到N的排列,找到连续的段(越短越好),代表的集合相同。

    思路:每次找到对应的位置,如果最远的对应位置和当前相同,说明这段集合相同。

    Map+clear: 3525ms

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    map<string, int>Map;
    int f[maxn];
    vector<int>ans;
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            int N,x,y;
            Map.clear();
            string s;
            scanf("%d",&N);
            rep(i,1,N){
                cin>>s;
                Map[s]=i;
            }
            rep(i,1,N){
                cin >> s;
                f[Map[s]] = i;
            }
            rep(i,1,N){
                if(i==f[i]) printf("1 ");
                else{
                    int maxx = f[i];
                    for(int j = i + 1; j <= maxx; j++){
                        if(f[j] > maxx)maxx = f[j];
                    }
                    printf("%d ",maxx-i+1);
                    i = maxx;
                }
            }
            puts("");
        }
        return 0;
    }
    View Code

    Map: 4227ms

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    map<string, int>Map;
    int f[maxn];
    vector<int>ans;
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            int N,x,y;
            string s;
            scanf("%d",&N);
            rep(i,1,N){
                cin>>s;
                Map[s]=i;
            }
            rep(i,1,N){
                cin >> s;
                f[Map[s]] = i;
            }
            rep(i,1,N){
                if(i==f[i]) printf("1 ");
                else{
                    int maxx = f[i];
                    for(int j = i + 1; j <= maxx; j++){
                        if(f[j] > maxx)maxx = f[j];
                    }
                    printf("%d ",maxx-i+1);
                    i = maxx;
                }
            }
            puts("");
        }
        return 0;
    }
    View Code

    unordered_map:2479ms

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    unordered_map<string, int>Map;
    int f[maxn];
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            Map.clear();
            int N,x,y;
            string s;
            scanf("%d",&N);
            rep(i,1,N){
                cin>>s;
                Map[s]=i;
            }
            rep(i,1,N){
                cin >> s;
                f[Map[s]] = i;
            }
            rep(i,1,N){
                if(i==f[i]) printf("1 ");
                else{
                    int maxx = f[i];
                    for(int j = i + 1; j <= maxx; j++){
                        if(f[j] > maxx)maxx = f[j];
                    }
                    printf("%d ",maxx-i+1);
                    i = maxx;
                }
            }
            puts("");
        }
        return 0;
    }
    View Code

    这告诉我们map的效率和map的大小有关,所以要及时的clear。 而我如果用set,一位set一直在erase,元素会慢慢表少,所以二分的速度会更快。

    set: 3010ms

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    set<string>s;
    string a[maxn],b[maxn];
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            int N,x,y,tot=0;
            scanf("%d",&N);
            rep(i,1,N) cin>>a[i];
            rep(i,1,N) cin>>b[i];
            rep(i,1,N) {
                tot++;
                if(s.find(a[i])!=s.end()) s.erase(a[i]);
                else s.insert(a[i]);
                if(s.find(b[i])!=s.end()) s.erase(b[i]);
                else s.insert(b[i]);
                if(s.empty()) {
                    printf("%d ",tot);
                    tot=0;
                }
            }
            puts("");
        }
        return 0;
    }
    View Code

    (但是主要的时间还是在输入输出那里。

    W .Wormhole

    pro:给定三维的N个点,有一些点对可以互通,其他的点对距离是欧几里得距离。Q次询问点对最近距离。

    sol:folyd。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=100;
    typedef long long ll;
    struct node
    {
        double x, y, z;
        double operator - (const node& a)const
        {
            return (sqrt((x - a.x) * (x - a.x) + (y - a.y) * (y - a.y) + (z - a.z) * (z - a.z)));
        }
    }a[maxn];
    map<string, int>Map;
    double dis[100][100];
    int main()
    {
        int T, cases = 0;
        scanf("%d", &T);
        while(T--)
        {
            memset(dis, 0, sizeof(dis));
            Map.clear();
            int n, m;
            scanf("%d", &n);
            string s, s1;
            for(int i = 1; i <= n; i++)
            {
                cin >> s >> a[i].x >> a[i].y >> a[i].z;
                Map[s] = i;
            }
            for(int i = 1; i <= n; i++)
            {
                for(int j = i + 1; j <= n; j++)
                {
                    dis[i][j] = dis[j][i] = a[i] - a[j];
                    //cout<<dis[i][j]<<endl;
                }
            }
            cin >> m;
            while(m--)
            {
                cin >> s >> s1;
                dis[Map[s]][Map[s1]] = 0;
            }
            for(int k = 1; k <= n; k++)
                for(int i = 1; i <= n; i++)
                    for(int j = 1; j <= n; j++)
                        dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
            cin >> m;
            cout<<"Case "<<++cases<<":
    ";
            while(m--)
            {
                cin >> s >> s1;
                cout<<"The distance from "<<s<<" to "<<s1<<" is "<<(ll)(dis[Map[s]][Map[s1]]+0.5)<<" parsecs.
    ";
            }
        }
        return 0;
    }
    View Code

    V .Towers

    pro:给定N,让填数独,然后给出(N+2)*(N+2)的矩阵,里面N*N的数字或者未知,周围4行表示从那个方向看过去的LIS。N<=5

    sol:搜索,需要及时减枝。 check函数就是给个方向的判定。 只跑了30ms,估计包本来就可以暴力一点,即到了边界再减枝?

           减枝1:对于每填一个数,就看和上面的数字是否有重复。

           减枝2:对于每个数,看左边和上边看过去的LIS已经超过题目描述,退出。

           判定3:对于右边界和下边界,检查从右和下看过去的LIS。

    #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=130;
    char c[9][9],ans[9][9];
    int vis[9][9],N;
    int get(int x,int y,int tx,int ty,int X,int Y)
    {
        int res=0,now=0;
        while(1){
            x+=tx; y+=ty;
            if(ans[x][y]>now) now=ans[x][y],res++;
            if(x==X&&y==Y) return res;
        }
        return res;
    }
    bool check(int u,int v)
    {
        rep(i,1,u-1) if(ans[u][v]==ans[i][v]) return false;
        if(c[u][0]!='-'){
            int t=get(u,0,0,1,u,v);
            if(t>c[u][0]-'0') return false;
            if(v==N&&t!=c[u][0]-'0') return false;
        }
        if(c[0][v]!='-'){
            int t=get(0,v,1,0,u,v);
            if(t>c[0][v]-'0') return false;
            if(u==N&&t!=c[0][v]-'0') return false;
        }
        if(v==N&&c[u][N+1]!='-'){
            if(get(u,N+1,0,-1,u,1)!=c[u][N+1]-'0') return false;
        }
        if(u==N&&c[N+1][v]!='-'){
            if(get(N+1,v,-1,0,1,v)!=c[N+1][v]-'0') return false;
        }
        return true;
    }
    bool dfs(int u,int v)
    {
        if(u==N+1&&v==1) {
            return true;
        }
        int L=1,R=N;
        if(c[u][v]!='-') L=R=c[u][v]-'0';
        rep(i,L,R){
            if(!vis[u][i]){
                vis[u][i]=1; ans[u][v]=i;
                if(v<N){
                    if(check(u,v)){
                        if(dfs(u,v+1)) return true;
                    }
                }
                else{
                    if(check(u,v))
                    {
                        if(dfs(u+1,1)) return true;
                    }
                }
                vis[u][i]=0;
            }
        }
        return false;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&N);
            memset(vis,0,sizeof(vis));
            rep(i,0,N+1) scanf("%s",c[i]);
            if(!dfs(1,1)) puts("no
    ");
            else {
                rep(i,1,N) {
                    rep(j,1,N) putchar(ans[i][j]+'0');
                    puts("");
                }
                puts("");
            }
        }
        return 0;
    }
    View Code

    T .Runes

    pro:给定等式,其中有不超过6个问号,让你填一个相同的未出现过的数字,使等式满足。

    sol:枚举。注意负号,0等情况。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=100;
    typedef long long ll;
    bool judge(char s[], int x, ll& y)
    {
        int n = strlen(s);
        char s1[110];
        memcpy(s1, s, sizeof(s1));
        for(int i = 0; i < n; i++)
        {
            if(s1[i] == '?')s1[i] = '0' + x;
        }
        if(s1[0] == '-' && s1[1] == '0')return false;
        if(s1[0] == '0' && n != 1)return false;
        bool flag;
        if(s1[0] == '-')flag = 1;
        else flag = 0;
        y = 0;
        for(int i = flag; i < n; i++)y = y * 10 + s1[i] - '0';
        if(flag)y = -y;
    }
    char s[110], s1[110], s2[110], s3[110];
    int vis[15];
    int main()
    {
        int T, cases = 0;
        scanf("%d", &T);
        while(T--)
        {
            memset(s1, 0, sizeof(s1));
            memset(s2, 0, sizeof(s2));
            memset(s3, 0, sizeof(s3));
            memset(vis, 0, sizeof(vis));
            scanf("%s", s);
            int n = strlen(s), tmp, tmp1;
            for(int i = 0; i < n; i++)
            {
                if((isdigit(s[i]) || s[i] == '?') && (s[i + 1] == '+' || s[i + 1] == '-' || s[i + 1] == '*'))
                {
                    tmp = i + 1;
                    break;
                }
            }
            for(int i = 0; i < n; i++)if(s[i] == '='){tmp1 = i;break;}
            for(int i = 0; i < n; i++)if(isdigit(s[i]))vis[s[i] - '0'] = 1;
            for(int i = 0; i < tmp; i++)s1[i] = s[i];
            for(int i = tmp + 1, j = 0; i < tmp1; i++, j++)s2[j] = s[i];
            for(int i = tmp1 + 1, j = 0; i < n; i++, j++)s3[j] = s[i];
            bool ok = 0;
            for(int i = 0; i <= 9; i++)
            {
                if(vis[i])continue;
                ll a, b, c;
                bool flag = 0;
                if(judge(s1, i, a) && judge(s2, i, b) && judge(s3, i, c))
                {
                    if(s[tmp] == '-' && a - b == c)flag = 1;
                    if(s[tmp] == '+' && a + b == c)flag = 1;
                    if(s[tmp] == '*' && a * b == c)flag = 1;
                }
                if(flag)
                {
                    ok = 1;
                    printf("%d
    ", i);
                    break;
                }
            }
            if(!ok)printf("-1
    ");
        }
        return 0;
    }
    View Code

    Q .Number Game

    pro:双人博弈,给定一个N的排列,Alice先手,Bob后手,他们轮流取,取到数字1的胜,能取走一个数字的条件是两旁没有比它大的数字。

    sol:我们发现,只有和1相邻的连续区间是要考虑的; 之外的区间因为一定可以按一定顺序取完,所以只考虑奇偶性。

    即用dp[L][R][k]保存先手的情况:[L,R]是当前包含数字1的区间,k是此区间外的未取的个数奇偶性。然后就可以记忆化搜索了。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=110;
    int dp[maxn][maxn][2],a[maxn],pos;
    int dfs(int L,int R,int k)
    {
        if(L==R) return 1;
        if(dp[L][R][k]!=-1)
          return dp[L][R][k];
        if(k==1&&!dfs(L,R,0)) dp[L][R][k]=1;
        rep(i,L,R){
            bool F=true;
            if(i-1>=L&&a[i-1]>a[i]) F=false;
            if(i+1<=R&&a[i+1]>a[i]) F=false;
            if(!F) continue;
            if(i==pos) dp[L][R][k]=1;
            else {
                if(i<pos){
                    if(!dfs(i+1,R,(k+i-L)&1)) dp[L][R][k]=1;
                }
                else {
                    if(!dfs(L,i-1,(k+R-i)&1)) dp[L][R][k]=1;
                }
            }
        }
        if(dp[L][R][k]==-1) dp[L][R][k]=0;
        return dp[L][R][k];
    }
    int main()
    {
        int N,T;
        scanf("%d",&T);
        while(T--){
           scanf("%d",&N);
           rep(i,1,N){
              scanf("%d",&a[i]);
              if(a[i]==1) pos=i;
           }
           memset(dp,-1,sizeof(dp));
           dfs(1,N,0);
           if(dp[1][N][0]) puts("Alice");
           else puts("Bob");
        }
        return 0;
    }
  • 相关阅读:
    解决THINKCMF后台文章的相册图集只能上传一个图片的问题
    WordPress 在function.php 文件中方法中the_XXX方法失效
    Windows 增强版任务管理器-Process Explorer
    从Linux服务器下载网站文件
    SQLSERVER 免费对比数据库结构和数据的工具支持:SQL Server 2012, SQL Server 2008 and SQL Server 2005
    [UE4]蓝图继承方法:重写父类方法时,增加父类方法调用
    [UE4]蓝图使用GameMode重构
    [UE4]控制台命令,生成机器人
    [UE4]区分敌我
    [UE4]AnimOffset偏移动画
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10441962.html
Copyright © 2020-2023  润新知