2018 年山东省第九届ACM省赛部分题解

A题 贪心瞎搞

看第二个样例
s:ELLY t:KRIS
先对两个字符串排序 如果s[i]<=t[i]直接转换,否则KRS部分循环一下求解
1.ELLY IKRS
2.ELLY IRSK
3.ELLY ISKR
求这三种情况的最小花费就好了。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;
string s,t;
int judge()
{
    int res=0;
    for (int i=0;s[i];i++) 
         res += s[i]<=t[i] ? t[i]-s[i] : 26-s[i]+t[i];
    return res;
}
int main()  
{
    ios_base::sync_with_stdio(0); cin.tie(0);
    while (cin>>s>>t)
    {
        sort(s.begin(),s.end());
        sort(t.begin(),t.end());
        int ans=judge();
        for (int i=0;s[i];i++) if (s[i]>t[i])
        {
            for (int j=i;s[j];j++)
            {
                t.push_back(t[i]);
                t.erase(i,1);
                ans=min(ans,judge());
            }
            break;
        }
        cout<<ans<<endl;
    }
    return 0;
}

C 最小生成树 签到题

#include<bits/stdc++.h>
using namespace std;
typedef long long LL; 
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;

int main()  
{
    ios_base::sync_with_stdio(0); cin.tie(0);
    int T;
    cin>>T;
    while (T--)
    {
        int n,x,minx=INF;
        LL sum=0;
        cin>>n;
        for (int i=1;i<=n;i++)
        {
            cin>>x;
            sum+=x;
            if (x<minx) minx=x;
        }
        if(n==1) cout<<0<<endl;
        else cout<<sum+1LL*minx*(n-2)<<endl;
    }
    return 0;
}

D 树剖?然而我并不会。
应该数据比较水,我的树上贪心复杂度能到O(4W*6W),按理说应该会超时,以后补树剖吧。
注意题目中说明的 魔法要从叶子节点开始升级,一直升级到最顶层魔法(也就是到节点0)产生的能量才有效。
所以6节点升级两个魔法到3,每个能产生4能量,3节点升级这两个魔法到2,就变成每个魔法产生9能量(累加起来好计算),5节点升级一个魔法到2,产生3能量。
2节点只能升级两个魔法,但是现在有三个,只能贪心选两个产生能量多的喽。

#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
typedef long long LL; 
typedef pair<int,int> PII;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;

vector<int> e[MAXN];
int num[MAXN],power[MAXN];
void dfs(int u, priority_queue<PII> &x)
{
    if (e[u].empty())
    {
        x.push(mp(power[u],num[u]));
        return;
    }
    priority_queue<PII> y;
    for (int v:e[u]) dfs(v,y);
    while (!y.empty() && num[u])
    {
        PII tmp = y.top(); y.pop();
        tmp.first+=power[u];
        if (tmp.second <= num[u]) num[u]-=tmp.second;
        else tmp.second=num[u],num[u]=0;
        x.push(tmp);
    }
}
int main()  
{
    ios_base::sync_with_stdio(0); cin.tie(0);

    int n;
    cin>>n;
    for (int i=1,x;i<=n;i++)
    {
        cin>>x>>num[i]>>power[i];
        e[x].push_back(i);
    }
    num[0]=INF;
    priority_queue<PII> x;
    dfs(0,x);
    LL ans=0;
    while (!x.empty())
    {
        ans+=1LL*x.top().first*x.top().second;
        x.pop();
    }
    cout<<ans<<endl;
    return 0;
}

E 比赛读错题意了,难受。存在j< i且a[j]< a[i],那么a[i]是“good”的,删掉一个数,让“good”的数最多,数量相同的有多个,删掉最小的那个。 统计删掉a[i]会少多少个“good”的数就好了。维护数组里两个最小值,如果都比a[i]小,那么a[i]一定是“good”,如果只有一个比a[i]小,删掉小的那个a[i]就不是“good”了。

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 5;
int a[MAXN],num[MAXN];

int main()
{
    ios_base::sync_with_stdio(0); cin.tie(0);
    int T;
    cin>>T;
    while (T--)
    {
        memset(num,0,sizeof num);
        int n;
        cin>>n;
        for (int i=1,idx=1,x=INF,y=INF;i<=n;i++)
        {
            cin>>a[i];
            if (y<a[i]) num[i]++;
            else if (x<a[i]) y=a[i],num[i]++,num[idx]++;
            else y=x,x=a[i],idx=i;
        }
        int idx=1;
        for (int i=2;i<=n;i++)
        {
            if (num[idx]==num[i]&&a[i]<a[idx]) idx=i;
            if (num[idx]>num[i]) idx=i;
        }
        cout<<a[idx]<<endl;
    }
    return 0;
}

F 明显容斥,不要问我为什么写的这么麻烦。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;

int main()
{
    ios_base::sync_with_stdio(0); cin.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
        LL l1,l2,l3,l4,r1,r2,r3,r4,ans;
        cin>>l1>>r1>>l2>>r2>>l3>>r3>>l4>>r4;
        //a,b,c,d对应四区间
        LL a=r1-l1+1,b=r2-l2+1,c=r3-l3+1,d=r4-l4+1;
        //ab对应前两区间可能取相同元素个数,下同
        LL ab = max(min(r1,r2)-max(l1,l2)+1,0LL);
        LL bc = max(min(r2,r3)-max(l2,l3)+1,0LL);
        LL cd = max(min(r3,r4)-max(l3,l4)+1,0LL);
        LL ad = max(min(r1,r4)-max(l1,l4)+1,0LL);
        LL abc = max(min(min(r1,r2),r3)-max(max(l1,l2),l3)+1,0LL);
        LL abd = max(min(min(r1,r2),r4)-max(max(l1,l2),l4)+1,0LL);
        LL acd = max(min(min(r1,r3),r4)-max(max(l1,l3),l4)+1,0LL);
        LL bcd = max(min(min(r2,r3),r4)-max(max(l2,l3),l4)+1,0LL);
        LL abcd = max(min(min(r1,r2),min(r3,r4))-max(max(l1,l2),max(l3,l4))+1,0LL);

        ans = a*b%MOD*c%MOD*d%MOD;
        //减掉不满足一个条件的
        ans -= ab*c%MOD*d%MOD; //a==b
        ans -= a*bc%MOD*d%MOD; //b==c
        ans -= a*b%MOD*cd%MOD; //c==d
        ans -= ad*b%MOD*c%MOD; //a==d
        //加上多减的满足两个条件的
        ans += abc*d%MOD; //a==b b==c
        ans += abd*c%MOD; //a==b a==d
        ans += acd*b%MOD; //a==d c==d
        ans += bcd*a%MOD; //b==c c==d
        ans += ab*cd%MOD; //a==b c==d
        ans += ad*bc%MOD; //a==d b==c
        //减掉多加的满足四个条件的
        ans -= 3*abcd;
        cout<<(ans%MOD+MOD)%MOD<<endl;
    }
    return 0;
}

G NIM博弈+DP
NIM和为0时Bob能获胜,也就是求去掉几堆石子后,剩下的石子亦或值为零的个数。我们可以求去掉的这几堆石子亦或值等于所有石子亦或值的个数。
dp数组开二维, 一维是几堆石子,一维是亦或值,里面保存符合条件的个数。
dp方程:dp[i+1][j^x] = (dp[i+1][j^x] + dp[i][j]) % MOD;,具体含义看代码吧。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
LL dp[11][1111];
int main()
{
    ios_base::sync_with_stdio(0); cin.tie(0);

    int T;
    cin>>T;
    while (T--)
    {
        memset(dp,0,sizeof dp); dp[0][0]=1;
        int n,d,sum=0,x;
        cin>>n>>d;
        while(n--)
        {
            int x;
            cin>>x;
            sum^=x;
            for (int i=d-1;i;i--)
                for (int j=0;j<1024;j++)
                    dp[i+1][j^x] = (dp[i+1][j^x] + dp[i][j]) % MOD;
            dp[1][x]++;
        }
        LL ans=0;
        for (int i=0;i<=d;i++)
            ans = (ans+dp[i][sum])%MOD;
        cout<<ans<<endl;
    }
    return 0;
}

H题 %SDU大佬
找规律可发现一块多米诺骨牌最多只会动一次除非往反方向走,又因为骨牌动一下等于空格向上/下/左/右方向移动两格,所以直接宽度优先搜索空格可以到的位置有多少个就是有多少解

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;

int n,m,k;
int mmap[11][11111];
int dx[] = {-1,0,1,0};
int dy[] = {0,1,0,-1};
queue<PII> que;
int bfs()
{
    for (int i=1,f=1;i<=n&&f;i++)
        for (int j=1;j<=m&&f;j++)
            if(!mmap[i][j])
            {
                f=0;
                que.push(make_pair(i,j));
            }
    int ans=0;
    while (!que.empty())
    {
        int x=que.front().first, y=que.front().second; 
        que.pop();
        for (int i=0;i<4;i++)
            if (mmap[x+dx[i]][y+dy[i]]!=0 && mmap[x+dx[i]][y+dy[i]] == mmap[x+dx[i]*2][y+dy[i]*2])
            {
                ans++;
                que.push(make_pair(x+dx[i]*2,y+dy[i]*2));
            }
    }
    return ans;
}
int main()
{
    ios_base::sync_with_stdio(0); cin.tie(0);

    while(cin>>n>>m>>k)
    {
        memset(mmap,0,sizeof mmap);
        for (int i=1,a,b,c,d,cnt=1;i<=k;i++,cnt++)
        {
            cin>>a>>b>>c>>d;
            mmap[a][b]=cnt;
            mmap[c][d]=cnt;
        }
        cout<<bfs()<<endl;
    }
    return 0;
}
阅读更多
换一批

没有更多推荐了,返回首页