SWUSTACM 2017周赛一

A:多推几组样例可以发现合法的情况下,答案就是a/k+b/k,由于打的比赛场数

是完整的,所以不存在的条件就是a%k=0并且b不等于0或者b%k=0并且a不等于0

B:以图片上的字母对称,注意题上的i是对称的。

C:

方法一:前缀和加上二分,因为是整数,前缀和满足递增。由于查询的值

<=5000,记忆化一下答案就可以了。二分的过程中,当二分到的和大于5000可以

剪枝。

方法二:利用two pointer O(n)解决。也要记忆化答案来优化。这个题只要记忆化

答案就放过了。下面这份代码跑了1996ms。

#include 
using namespace std;
const int maxn = 100010;
int ans[5010],a[maxn];
int n, q, x;

int main()
{
    while(~scanf("%d%d",&n,&q))
    {
        for(int i=1; i<=n; i++) scanf("%d", &a[i]);
        memset(ans,-1,sizeof(ans));
        while(q--){
            scanf("%d", &x);
            if(ans[x]!=-1){
                printf("%d\n", ans[x]);
            }
            else{
                int r=1,sum=0,anss=0;
                for(int l=1; l<=n; l++){
                    while(r<=n&&sum+a[r]<=x){
                        sum+=a[r];
                        r++;
                    }
                    anss=max(anss,sum);
                    sum-=a[l];
                }
                printf("%d\n", anss);
                ans[x]=anss;
            }
        }
    }
    return 0;
}

D:DFS,显然已经损坏的木板是不能走的,那么假如能够不经过损坏的木板走到

终点并且终点这块木板是损坏的,那么就是有解的,相反就是无解。

#include
using namespace std;
int n, m, r1, c1, r2, c2;
char mat[35][35];
bool vis[35][35];
bool test = false;
bool valid(int a, int b)
{
    if(a == r2 && b == c2)return true;
    return !(a < 1 || b < 1 || a > n || b > m || mat[a][b] == 'X');
}
void dfs(int i, int j)
{
    if(!valid(i, j))
        return;
    if(i == r2 && j == c2 && mat[i][j] == 'X')
    {
        test = true;
    }
    mat[i][j] = 'X';
    dfs(i + 1, j);
    dfs(i - 1, j);
    dfs(i, j + 1);
    dfs(i, j - 1);
}
int main()
{
    while(scanf("%d%d", &n, &m) != EOF)
    {
        test = false;
        memset(vis, false, sizeof vis);
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                cin >> mat[i][j];
            }
        }
        cin >> r1 >> c1 >> r2 >> c2;
        mat[r1][c1] = '.';
        dfs(r1, c1);
        cout << (test ? "YES" : "NO")<return 0;
}

E:模拟题,注意后导0,然后像高精度那样模拟即可。

#include 
using namespace std;
char s[505];
string ans1,ans2;
int main()
{
    while(cin>>s)
    {
        int len=strlen(s);
        int pos;
        int xx=0,flag=0;
        for(int i=0; iif(s[i]=='.') pos=i;
            else if(s[i]=='e') flag=1;
            else if(flag&&isdigit(s[i]))      xx=(xx*10+s[i]-'0');
        }
        pos=pos+xx;
        ans1="";
        ans2="";
        for(int i=0; iif(s[i]=='.') continue;
            if(s[i]=='e') break;
            ans1+=s[i];
        }
        int curlen=ans1.size();
        for(int i=curlen; i<500; i++) ans1+='0';
        for(int i=0; i'.';
        for(int i=pos; i<500; i++) ans2+=ans1[i];
        int le=(int)ans2.size();
        while(ans2[--le]=='0');
        if(ans2[le]=='.') le--;
        ans2[le+1]='\0';
        for(int i=0; i1; i++) cout<cout<return 0;
}

F:概率DP。用dp[x][y]记录当前还剩x张白卡,y张红卡卡牧师获胜的概率。考虑

这个DP的转移,牧师可以直接摸到白卡,如果红卡小于两张,但前面保证有卡,

所以红卡被牧师抽到,术士抽到白卡,赢的概率为0,所以让牧师先抽一张红卡,

然后术士再抽一张红卡,分别计算概率,然后用这个概率乘上后面转移到的状态即

可。

#include
using namespace std;
const int maxn=1005;
double dp[maxn][maxn];
int vis[maxn][maxn];
double dfs(int x,int y)
{
    if(x<=0) return 0;
    if(y<=0) return 1;
    if(vis[x][y]) return dp[x][y];
    vis[x][y]=1;
    double ans=1.0*x/(x+y);
    if(y>=2)
    {
        double k=1.0*y/(x+y);
        y--;
        k*=1.0*y/(x+y);
        y--;
        dp[x-1][y]=dfs(x-1,y);
        dp[x][y-1]=dfs(x,y-1);
        ans+=k*(1.0*x/(x+y)*dp[x-1][y]+1.0*y/(x+y)*dp[x][y-1]);
    }
    return ans;
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&a,&b))
    {
        printf("%.9f\n",dfs(a,b));
    }
    return 0;
}

你可能感兴趣的:(ACM/ICPC_SWUST,OJ)