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;
}
原文地址:https://www.cnblogs.com/hua-dong/p/10441962.html