CSP2020题解

CSP2020题解

T1:儒略日

Description

Solution

考虑按特殊日期分段,然后每段的4年/400年是一样的于是就可以把循环的范围缩小,然后就是各种讨论

写的时候和考后发现的问题是:

  • 第一年是366天先减了个365
  • 1582年10月会输出32日
  • 1582年前的闰年会输出3月0日
  • 没开long long

主要都是细节的问题

#include<bits/stdc++.h>

using namespace std;

#define LL long long

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

const int Julian = 4713;

int Q;
int num[14] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int ansY,ansM,ansD;
LL tot;

inline bool is_rn1(int x)
{
    if((x - 1) % 4 == 0) return 1;
    else return 0;
}

inline bool is_rn2(int x)
{
    if(x % 4 == 0) return 1;
    return 0;
}

inline bool is_rn3(int x)
{
    if(x % 400 == 0) return 1;
    else if(x % 100 == 0) return 0;
    else if(x % 4 == 0) return 1;
    return 0;
}

int main()
{
    LL a = ((4713 - 1) / 4) * (365 * 3 + 366) + 366; 
    LL b = (365 * 3 + 366);
    LL c = ((1582 - 1) / 4) * b;
    c +=  365;
    LL d = c + 355; 
    tot = 400 * 365 + 97;
    Q = read();
    while(Q--)
    {
        LL r = read();
        ansY = 0,ansM = 1,ansD = 1;
        if(r < a)
        {
            int res1 = r / (b);// 4 years
            ansY = 4713 - res1 * 4;
            r -= res1 * b;
            if(r >= 366) {    r-=366,ansY--;while(r >= 365) r-=365,ansY--;}
            int cur = num[1];
            for(int i=1;i<=11&&r>=cur;i++)
            {    
                r -= cur; 
                cur = num[i+1];        
                if(is_rn1(ansY)&&i == 1) cur++;
                ansM++;
            }
            ansD += r;
            printf("%d %d %d BC\n",ansD,ansM,ansY);
        }
        else if(r >= a)
        {
            r -= a;
            ansY = 1,ansM = 1,ansD = 1;
            LL res1 = r/b;
            if(r < c)// 1 ~ 1582
            { 
                r -= res1 * b;
                ansY = 1 + res1 * 4;
                if(r >= 365) r-= 365,ansY++;
                if(r >= 365) r-= 365,ansY++;
                if(r >= 365) r -= 365,ansY++;
                if(r >= 366) r-=366,ansY++;    
                int cur = num[1];
                for(int i=1;i<=11&&r>=cur;i++)
                {
                    r -= cur;     
                    cur = num[i+1];
                    if(is_rn2(ansY)&&i == 1) cur++;
                    ansM++;
                }
                ansD += r;
                printf("%d %d %d\n",ansD,ansM,ansY);
            }
            else if(r >= c && r < d)
            {
                ansY = 1582;ansM = 1;ansD = 1;
                r -= c;
                for(int i=1;i<=12&&(r>=num[i]||(i == 10 && (r + 10 >= num[i])));i++)
                {
                    int cur = num[i];
                    if(i == 10 && r + 10 >= num[i]) r = r + 10 - num[i];
                    else r -= num[i];
                    ansM++;
                }
                if(ansM == 10)
                {
                    if(r < 4) ansD += r;
                    else ansD += r + 10;
                }
                else ansD += r;
                printf("%d %d %d\n",ansD,ansM,ansY);
            }
            else if(r >= d)
            {
                ansY = 1583;
                r -= d;
                int res1 = r/tot;
                ansY += res1 * 400;
                r -= res1 * tot;
                while(r)
                {
                    /*if(r >= 365 * 3 + 366)
                    {
                        r -= 365 * 3 + 366;
                        ansY += 4;
                        continue;        
                    } */
                    bool fl = is_rn3(ansY);
                //    cout << fl << endl;
                    if(fl&&r>=366)
                    {
                        r -= 366;
                        ansY++;
                        continue;
                    }
                    if(fl==0&&r>=365)
                    {
                        r-= 365;
                        ansY++;
                        continue;
                    }
                    //if(flag) cout << ansY << " " << flag << endl;
                    ansM = 1,ansD = 1;
                    int cur = num[1];
                    for(int i=1;i<=11&&r>=cur;i++)
                    {
                        r -= cur; 
                        ansM++;                    
                        cur = num[i+1];
                        if(fl&&i == 1) cur++;
                    }
                    if(r < cur) ansD += r,r = 0;
                    if(!r) break;
                    ansY++;                    
                }
                printf("%d %d %d\n",ansD,ansM,ansY);
            }
        }
        
    }
    return 0;
}
View Code

 

T2 动物园

Description

Solution

需要注意的是特殊边界

#include<bits/stdc++.h>

using namespace std;

#define LL long long
#define ULL unsigned long long

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

const int MAXN = 1e6 + 10;

int n,m,c,k;
ULL a[MAXN];
int p[MAXN];
int col[MAXN];
vector<int>G[100 + 10];

int main()
{
    n = read(),m = read(),c = read(),k = read();
    ULL sum = 0;
    if(n == 0 && k == 64)
    {
        cout << "18446744073709551616" << endl;
        return 0;
    }
    for(int i=1;i<=n;i++) a[i] = read(),sum |= a[i];
    for(int i=1;i<=m;i++)
    {
        p[i] = read();int q = read();
        G[p[i]].push_back(i);
    }
    for(int i=0;i<k;i++)
    {
        if((1ULL << i) & sum)
        {
            for(int j=0;j<G[i].size();j++)
            {
                col[G[i][j]] = 1;
            }
        }
    }
    int cur = 0;
    for(int i=0;i<k;i++)
    {
        int res = 1;
        for(int j=0;j<G[i].size();j++) res &= col[G[i][j]];
        if(res) cur++;
    }
    cout << (1ULL << cur) - n << endl;
    return 0;
}
View Code

 

T3 函数调用

Description

Solution

考虑到乘法是全局操作,很容易想到把答案转化为原数值乘上所以乘法操作 加上 每个加法操作最后的值

显然加法操作最后的值只会被后面涉及到他的乘法操作影响

于是考虑维护一个操作的后缀积

这个后缀积由两部分组成,一部分是后面独立的操作,一部分有可能是当前这个操作体系中在他后面的乘法操作

这道题的核心就在于如何维护一个操作体系中乘法操作的影响

显然这样的一个操作体系是个DAG,可以拓扑做

考场上思路比较乱,写的有点麻烦,差点没调出来。。。

#include<bits/stdc++.h>

using namespace std;

#define LL long long

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

const int MAXM = 1000000 + 5;
const int MAXN = 200000 + 10; 
const int MOD = 998244353;

int n,m;
LL a[MAXN];

struct Query
{
    int opt;
    LL v;
    LL vv;
}b[MAXN];
LL mull[MAXN],val[MAXN];
struct Edge
{
    int to;
    int next;
    LL w;
}G[MAXM + MAXN];
int head[MAXN],cnt;
int Q;
int f[MAXN];
int deg[MAXN];
LL W[MAXN];
bool vis[MAXN];
queue<int>q;
inline void addedge(int u,int v)
{
    G[++cnt].to = v;G[cnt].next = head[u];head[u] = cnt;return;
}

inline void dfs(int x)
{
    vis[x] = 1;
    int sz = 0;
    LL res = 1;
    for(int i=head[x];i;i=G[i].next)
    {
        sz++;
        int v = G[i].to;
        if(v > m)
        {
            return;
        }
        if(!vis[v]) dfs(v);
        G[i].w = res;
        res = res * val[v] % MOD;
    }
    if(sz) val[x] = res;
    return;
}

inline void solve()
{
    for(int i=1;i<=m;i++)
    {
        if(!deg[i])
            dfs(i);
    }
}

LL dp[MAXN],add[MAXN];

inline void toppsort()
{
    for(int i=1;i<=m;i++) dp[i] = W[i];
    for(int i=1;i<=m;i++) if(!deg[i]) q.push(i),dp[i] = W[i];
    while(q.size())
    {
        int u = q.front();q.pop();
        for(int i=head[u];i;i=G[i].next)
        {
            int v = G[i].to;
            if(v > m){add[v - m] = (add[v - m] + dp[u] * b[u].vv%MOD) % MOD;}
            else dp[v] = (dp[v] + dp[u] * G[i].w % MOD) % MOD;
            deg[v]--;
            if(!deg[v]) q.push(v);
        }
    }
}

int main()
{
    n = read();
    for(int i=1;i<=n;i++) a[i] = read();
    m = read();
    for(int i=1;i<=m;i++)
    {
        val[i] = 1;
        b[i].opt = read(),b[i].v = read();
        if(b[i].opt == 1) b[i].vv = read(),addedge(i,b[i].v + m),deg[b[i].v+m]++;
        if(b[i].opt == 2) val[i] = val[i] * b[i].v % MOD;
        if(b[i].opt == 3)
        {
            for(int j=1;j<=b[i].v;j++)
            {
                int cur = read();
                addedge(i,cur);
                deg[cur]++;
            }
        }
    }
    solve();
    Q = read();
    mull[Q+1] = 1;
    for(int i=1;i<=Q;i++) mull[i] = 1,f[i] = read();
    for(int i=Q;i>=1;i--) mull[i] = mull[i+1] * val[f[i]] % MOD;
    for(int i=1;i<=Q;i++)
    {
        if(b[f[i]].opt == 3)
        W[f[i]] += mull[i+1],W[f[i]] %= MOD;
    }
    toppsort();
    LL Mul = 1;
    for(int i=1;i<=Q;i++)
    {
        Mul = Mul * val[f[i]] % MOD;
        if(b[f[i]].opt == 1) add[b[f[i]].v] = (add[b[f[i]].v] + b[f[i]].vv * mull[i+1] % MOD) % MOD;
    }
    for(int i=1;i<=n;i++) 
        printf("%lld ",(a[i] * Mul % MOD + add[i]) % MOD);
    return 0;
}
/*
3
1 2 3
2
2 2
3 2 1 1
2
1 2
*/
View Code

 

T4 贪吃蛇

Description

Solution

考试时大概想到了70pts的做法,但是由于T3写太久了,没时间了。。。

容易想到两点:

  1. 如果这只蛇吃了只会不是最弱的蛇,那么他一定会吃
  2. 如果这只蛇吃了变成最弱的蛇且第二强的蛇吃掉他后不会变成最弱的蛇,他就一定不会吃

第二点的正确性取决于第一点 ,考虑第一点的不严谨证明:

  当前最强,次强,最弱,次弱 : A,B,C,D,显然 A-D > B-C

   A吃了D之后原序列变成了 B ,A-D,C,这时B吃了C后在原序列A-D的后面,也就是说A-D永远不可能成为最弱的

有了第一个结论,第二个结论显然

于是吃了变成最弱的蛇就变成了一个递归的问题,显然和到问题递归的层数相关

这个最大值,最小值显然可以拿set维护

但实际上每次吃掉后的蛇依旧有单调性,所以想“蚯蚓”那样维护即可

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0'||ch > '9');
    do
    {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    }while(ch >= '0' && ch <= '9');
    return f*x;
} 

const int MAXN = 1000000 + 10;

int T;
int n;
int a[MAXN];
pair<int,int>q1[MAXN],q2[MAXN];
int l1,l2,r1,r2,ans;
int Case;

inline void clear()
{
    memset(q1,0,sizeof(q1));
    memset(q2,0,sizeof(q2));
    l1 = 1;r1 = 0;
    l2 = 1;r2 = 0;
}

inline int size1()
{
    return r1 - l1 + 1;
}

inline int size2()
{
    return r2 - l2 + 1;
}

inline pair<int,int> checkmax()
{
    pair<int,int> res;
    if(r2 < l2 ||(r1 >= l1 && q1[r1] > q2[l2]))
    {
        res = q1[r1];r1--;
    }
    else res = q2[l2],l2++;
    return res;
}

int main()
{
//    freopen("snakes4.in","r",stdin);
    T = read();n = read();
    while(T--)
    {
        ++Case;
        ans = 0;
        clear();
        if(Case == 1) for(int i=1;i<=n;i++) a[i] = read();
        else
        {
            int k = read();
            for(int i=1;i<=k;i++)
            {
                int x = read(),y = read();
                a[x] = y;
             } 
        }
        for(int i=1;i<=n;i++)
        {
            pair<int,int> cur = make_pair(a[i],i);
            q1[++r1] = cur;
        }
        while(1)
        {
            if(size1() + size2() == 2) 
            {
                ans = 1;
                break;
            }
            pair<int,int> cur_min = q1[l1];l1++;
            pair<int,int> cur_max = checkmax();
            if(r1 >= l1 && q1[l1] < make_pair(cur_max.first - cur_min.first,cur_max.second)) q2[++r2] =  make_pair(cur_max.first - cur_min.first,cur_max.second);
            else
            {
                pair<int,int>cur = make_pair(cur_max.first - cur_min.first,cur_max.second);
                ans = size1() + size2() + 2;
                int cnt = 0,res = 0;
                while(1)
                {
                    cnt++;
                    if(size1() + size2() == 1)
                    {
                        if(cnt % 2 == 0) res++;
                        break;
                    }
                    pair<int,int> now = checkmax();now.first -= cur.first;
                    if((r1 >= l1 || r2 >= l2) && now > min(r2 >= l2 ?q2[r2]:make_pair(1<<30,1<<30),r1>=l1?q1[l1]:make_pair(1<<30,1<<30)))
                    {
                        if(cnt % 2 == 0) res++;
                        break;
                    }
                    cur = make_pair(now.first ,now.second);
                }    
                ans -= res;
                break;
            }
        }
        printf("%d\n",ans);
    }
}
View Code

 

posted @ 2020-11-24 21:05  wlzs1432  阅读(151)  评论(0编辑  收藏  举报