2021浙江省赛题解(A,C,F,G,J,L,M)

2021浙江省赛题解(A,C,F,G,J,L,M)

A.League of Legends

题解

签到题

直接求和判断一下

注意会爆 i n t int int以及相等的情况。

代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 2e5+7;
int a[10],b[10];
void solve(){
    rp(i,1,5) a[i]=read();
    rp(i,1,5) b[i]=read();
    ll sum1=0,sum2=0; 
    rp(i,1,5) sum1+=a[i],sum2+=b[i];
    if(sum1<sum2) cout<<"Red"<<endl;
    else cout<<"Blue"<<endl;
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();

    solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

C.Cube

题解

刚开始以为题意是判断是否是长方体。

然后写了长方体的判断方法,后面看样例发现是正方体后想到一个简单做法。

判断是否有 12 12 12个相等的棱, 12 12 12个相等的面对角线, 4 4 4个相等的体对角线,以及棱,面对角线和体对角线可以形成直角三角形(满足勾股定理)就行了。

代码
#include <bits/stdc++.h>
#define _for(i, a) for(int i = 0, le = (a); i < le; ++i)
#define _rep(i, a, b) for(int i = (a), le = (b); i <= le; ++i)
typedef long long LL;
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;

LL read() {
    LL x(0), f(1); char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}

struct poi {
    int x, y, z;
    poi(){}
    poi(int x, int y, int z):x(x), y(y), z(z) {}
    void sc() {
        x = read(), y = read(), z = read();
    }
    bool operator<(const poi b) const {
        if(x != b.x) return x < b.x;
        if(y != b.y) return y < b.y;
        if(z != b.z) return z < b.z;
        return 0;
    }
};

int T;
vector<poi> a;
set<poi> a4, ano4;
LL MaxDis;

int isEqu(LL a, LL b) {
    return a == b;
}

LL getDis(poi a, poi b) {
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z);
}

int isSqu(poi a, poi b, poi c, poi d) {
    vector<poi> t;
    t.push_back(a);
    t.push_back(b);
    t.push_back(c);
    t.push_back(d);
    vector<LL> vals;
    _for(i, 4) {
        _for(j, i) {
            vals.push_back(getDis(t[i], t[j]));
        }
    }
    sort(vals.begin(), vals.end(), greater<LL>());
    if(isEqu(vals[0], vals[2])) return 0;
    if(isEqu(vals[0], MaxDis)) return 0;

    if(!isEqu(vals[0], vals[1])) return 0;
    if(!isEqu(vals[2], vals[3])) return 0;
    if(!isEqu(vals[4], vals[5])) return 0;
    if(!isEqu(vals[4], vals[2])) return 0;
    return 1;
}

set<poi> getSqu() {
    set<poi> ans;
    _for(i, 8) {
        _for(j, i) {
            _for(k, j) {
                _for(l, k) {
                    if(isSqu(a[i], a[j], a[k], a[l])) {
                        ans.insert(a[i]);
                        ans.insert(a[j]);
                        ans.insert(a[k]);
                        ans.insert(a[l]);
                        return ans;
                    }
                }
            }
        }
    }
    return ans;
}

LL getMinDis(poi a) {
    LL ans = INF;
    for(poi i : ano4) {
        ans = min(getDis(a, i), ans);
    }
    return ans;
}

void init() {
    MaxDis = -1;
    a4.clear();
    ano4.clear();
}

int sol() {
    init();
    _for(i, 8) {
        _for(j, i) {
            if(!(a[i] < a[j]) && !(a[j] < a[i])) return 0;
        }
    }
    vector<LL> diss;
    _for(i, 8) {
        _for(j, i) {
            diss.push_back(getDis(a[i], a[j]));
        }
    }
    sort(diss.begin(), diss.end());
    _for(i, 12) {
        _for(j, i) {
            if(diss[i] != diss[j]) return 0;
        }
    }
    _for(i, 12) {
        _for(j, i) {
            if(diss[12 + i] != diss[12 + j]) return 0;
        }
    }
    _for(i, 4) {
        _for(j, i) {
            if(diss[24 + i] != diss[24 + j]) return 0;
        }
    }
    if(diss[0] + diss[12] != diss[24]) return 0;
    return 1;
}

int main() {
    // freopen("in.txt", "r", stdin);
    scanf("%d", &T);
    _for(i, T) {
        a.resize(8);
        _for(i, 8) a[i].sc();
        printf("%s\n", sol() ? "YES":"NO");
    }
    return 0;
}

F.Fair Distribution

题解

不难发现对于 n > m n>m n>m的情况直接输出 n − m n-m nm即可。
对于其他的情况我们可以推出一个公式。

推导过程如下:
我们假设 n n n减小成了 i i i 1 ≤ i ≤ n 1 \leq i \leq n 1in

那么这是 m m m就需要变成 ⌈ m i ⌉ ∗ i \lceil \frac{m}{i} \rceil*i imi

操作次数就是 n − i + ⌈ m i ⌉ ∗ i − m n-i+\lceil \frac{m}{i} \rceil*i-m ni+imim

整理可得原式等于
( ⌈ m i ⌉ − 1 ) ∗ i + n − m (\lceil \frac{m}{i} \rceil-1)*i+n-m (im1)i+nm

我们把上式中的上取整转换成下取整。

( ⌊ m + i − 1 i ⌋ − 1 ) ∗ i + n − m (\lfloor \frac{m+i-1}{i} \rfloor-1)*i+n-m (im+i11)i+nm

⇉ ⌊ m − 1 i ⌋ ∗ i + n − m \rightrightarrows \lfloor \frac{m-1}{i} \rfloor*i+n-m im1i+nm

这时我们就可分块维护 ⌊ m − 1 i ⌋ ∗ i \lfloor \frac{m-1}{i} \rfloor*i im1i,记录答案最小值就行了。

代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
    ll n,m;scl(n);scl(m);
    if(n>m) cout<<n-m<<endl;
    else{
        ll ans=inf;
        for(ll l=1,r;l<=n;l=r+1){
            r=min(n,(m-1)/((m-1)/l));
            ans=min(ans,(m-1)/l*l);
        }
        cout<<ans+n-m<<endl;
    }
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();

    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

G.Wall Game

题解

把每个坐标离散化成一个点。

对于每次占领操作,我们用并查集维护能够触碰的墙的个数。

对于一个坐标,最多能和六个相邻的坐标相连,我们枚举相邻几个个点能够触碰的墙的和 s u m sum sum以及自身产生的能够触碰的墙的个数 6 6 6

然后用容斥的思想减去需要消去的墙的个数。

这时分为两种来考虑。

一种是自身和相邻坐标消去的墙 c n t cnt cnt

另一种是相邻坐标中中消去的墙 m i n u s minus minus(其祖先节点不相等)。

注意需要判断相邻坐标祖先节点相同时的情况(去重),

最终该点的答案就是 s u m − 6 − c n t ∗ 2 − m i n u s ∗ 2 sum-6-cnt*2-minus*2 sum6cnt2minus2

对于每次查询操作,查询其祖先节点的答案即可。

代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 5e5+7;
int fa[N];
int w[N];
map<pii,int> mp;
int dir[6][2]={0,1,1,0,1,-1,0,-1,-1,0,-1,1};
int find(int x){
    return x==fa[x]?fa[x]:fa[x]=find(fa[x]);
}
void solve(){
    int n=read();
    int tot=0;
    while(n--){
        int op=read(),x=read(),y=read();
        if(op==1){
            mp[m_p(x,y)]=++tot;
            fa[tot]=tot;
            w[tot]=6;
            int sum=0;
            int minus=0;
            int cnt=0;
            set<int> ss;
            vector<pii> vv;
            rp(k,0,5){
                int nx=x+dir[k][0];
                int ny=y+dir[k][1];
                if(mp.find(m_p(nx,ny))==mp.end()) continue;
                int id=find(mp[m_p(nx,ny)]);
                vv.push_back(m_p(k,id));
                if(ss.find(id)!=ss.end()) cnt++;
                else{
                    cnt++;
                    sum+=w[id];
                    ss.insert(id);
                }
            }
            int len=vv.size();
            rp(k,0,len-1){
                rp(j,0,len-1){
                    if(vv[k].first==0&&vv[j].first==1&&vv[k].second!=vv[j].second) minus++;
                    if(vv[k].first==1&&vv[j].first==2&&vv[k].second!=vv[j].second) minus++;
                    if(vv[k].first==2&&vv[j].first==3&&vv[k].second!=vv[j].second) minus++;
                    if(vv[k].first==3&&vv[j].first==4&&vv[k].second!=vv[j].second) minus++;
                    if(vv[k].first==4&&vv[j].first==5&&vv[k].second!=vv[j].second) minus++;
                    if(vv[k].first==5&&vv[j].first==0&&vv[k].second!=vv[j].second) minus++;
                }
            }
            for(auto val:ss){
                // cout<<val<<" ";
                fa[val]=tot;
            }
            // cout<<endl;
            w[tot]=sum+w[tot]-2*cnt-2*minus;
            // cout<<w[tot]<<endl;
            // outval3(sum,cnt,minus);
        }
        else{
            cout<<w[find(mp[m_p(x,y)])]<<endl;
        }
    }
    // for(auto val:mp){
        // pii t=val.first;
        // outval3(t.first,t.second,find(mp[t]));
    // }
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();

    solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

J.Grammy and Jewelry

题解

算是比较套路的题。

根据贪心的原则,我们每次取一个宝珠后应该立马返回到原点。

而我们到这个宝珠的位置走的路和返回时走的路应该是最短路。

转换一下就是我们要取一个价值为 a [ i ] a[i] a[i]的宝珠,需要消耗容量为 2 ∗ d i s [ i ] 2*dis[i] 2dis[i]的时间( d i s [ i ] dis[i] dis[i]表示从 1 1 1 i i i的最短路)。

这样就转换成了经典的完全背包问题。

关于背包问题不懂的可以看经典的背包九讲。

代码
#include <bits/stdc++.h>
#define _for(i, a) for(int i = 0, le = (a); i < le; ++i)
#define _rep(i, a, b) for(int i = (a), le = (b); i <= le; ++i)
typedef long long LL;
#define INF 0x3f3f3f3f
const int N = 3007;
using namespace std;

LL read() {
    LL x(0), f(1); char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
vector<int> G[N];
int a[N];
int dis[N];
int vis[N];
int dp[N];
struct node{
    int u,w;
    friend bool operator <(node a,node b){
        return a.w>b.w;
    }
};
int n,m,T;
void Dijkstra(){
    priority_queue<node> q;
    _rep(i,1,n) dis[i]=0x3f3f3f3f;
    q.push(node{1,0});
    dis[1]=0;
    memset(vis,0,sizeof vis);
    while(!q.empty()){
        node t=q.top();
        q.pop();
        vis[t.u]=1;
        int u=t.u;
        int w=t.w;
        // cout<<u<<" "<<w<<endl;
        for(auto v:G[u]){
            // cout<<v<<" "<<dis[v]<<endl;
            if(!vis[v]&&dis[v]>w+1){
                dis[v]=w+1;
                q.push(node{v,dis[v]});
            }
        }
    }
}
int main() {
    // freopen("in.txt", "r", stdin);
    n=read(),m=read(),T=read();
    _rep(i,2,n) a[i]=read();
    _rep(i,1,m){
        int u=read(),v=read();
        if(u==v) continue;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    // for(int u=1;u<=n;u++){
    //     cout<<u<<endl;
    //     for(auto v:G[u]) cout<<v<<" ";
    //     cout<<endl;
    // }
    Dijkstra();
    // _rep(i, 1, n) printf("dis[%d]:%d\n", i, dis[i]);
    _rep(i, 1, n) {
        for(int j = dis[i] * 2; j <=T ; ++j) {
            dp[j] = max(dp[j], dp[j - dis[i] * 2] + a[i]);
        }
    }
    _rep(i, 1, T) printf("%d%s", dp[i], (i == T ? "\n":" "));
    return 0;
}

L.String Freshman

题解

c f cf cf上的题意有点错误,给的字符串应该是匹配串。

因此我们判断一下是否存在前缀子串的最长公共前后缀长度不为 0 0 0(即next数组不为 0 0 0)。

更简单的做法就是判断是否有字符和第一个字符相等即可。

代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
    int n=read();
    string s;cin>>s;
    rp(i,1,n-1){
        if(s[i]==s[0]){
            printf("Wrong Answer\n");
            return ;
        }
    }
    printf("Correct\n");
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();
    solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

M.Game Theory

题解

假结论题。

先说结论:输出 0.0000 0.0000 0.0000即可。

当时感觉题意有点模糊,后面读懂题意后验证了一下就交了。

首先我们知道每个学生是不知道 G r a m m y Grammy Grammy的选择,而又因为学生每次都是最优的选择,因此我们可以先算出一个学生在 [ 1 , 20 ] [1,20] [1,20]选择一个数后赢的分数的期望,每次都选择这 20 20 20个数中期望最大的即可。

我们写出计算期望的代码可以发现,每个数赢的分数的期望都是 0 0 0

而学生和 G r a m m y Grammy Grammy的分数又是互补的,只有一个输了,另一个才能赢。

因此 G r a m m y Grammy Grammy赢的分数的期望也是 0 0 0

代码
#include <bits/stdc++.h>
#define _for(i, a) for(int i = 0, le = (a); i < le; ++i)
#define _rep(i, a, b) for(int i = (a), le = (b); i <= le; ++i)
typedef long long LL;
using namespace std;
LL read() {
    LL x(0), f(1); char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
const int maxn = 100005;

int getSco(int G, int S) {
    if(G > S) return G - S - 10;
    if(S > G) return G - S + 10;
    return G - S;
}

double sco(int x) {
    double ans = 0;
    _rep(i, 1, 20) {
        ans += getSco(i, x);
    }
    return ans / 20.0;
}

int main() {
    // _rep(i, 1, 20) {
    //     printf("i:%d\tans:%.10f\n", i, sco(i));
    // }
    int x = read();
    printf("0.0000\n");
    return 0;
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值