CSP-S模拟2

都说T1T2是大水题,我鹤完题解之后还感觉奇奇妙妙收获满满,这就是差距吗

A. 谜之阶乘

TLE:要用两个阶乘的差算出n,就是把n用几个连续的数相乘表示出来,这几个连续的数都应该是n的因数,于是可以先把因数找到,再枚举以每个因数作为这几个连续的数相乘的右边界,往前循环的时候判断是否相等和是否连续。

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = -2;
const int N = 60;
const ll mod = 1e9 + 7;

int T, sq;
ll n, sz;
vector<ll> yin;
vector<pair<ll, ll> > ans;

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

int main()
{
    //freopen("factorial2.in", "r", stdin);
    //freopen("ww.txt", "w", stdout);
    T = read();
    while(T--)
    {
        n = read();
        ans.clear();
        yin.clear();
        if(n == 1)
        {
            printf("-1\n"); continue;
        }
        sq = sqrt(n);
        //printf("sq = %d\n", sq);
        yin.push_back(n);
        //if(sq * sq == n) yin.push_back(sq);
        for(int i=2; i<=sq; i++)
        {
            if(n % i == 0) 
            {
                yin.push_back(i); 
                if(i * i == n) break;
                yin.push_back(n/i);
            }
        }
        sort(yin.begin(), yin.end());
        sz = yin.size();
        /*for(ll i=0; i<sz; i++)
        {
            printf("%lld ", yin[i]);
        }
        printf("\n");*/
        for(ll i=0; i<sz; i++)
        {
            ll now = yin[i];
            if(now == n)
            {
                ans.push_back(make_pair(yin[i], yin[i]-1));
            }
            for(int j=i-1; j>=0; j--)
            {
                if(yin[j]+1 == yin[j+1])
                {
                    now *= yin[j];
                }
                else break;
                if(now == n)
                {
                    ans.push_back(make_pair(yin[i], yin[j]-1));
                    break;
                }
            }
        }
        sort(ans.begin(), ans.end());
        sz = ans.size();
        printf("%lld\n", sz);
        for(ll i=0; i<sz; i++)
        {
            printf("%lld %lld\n", ans[i].first, ans[i].second);
        }
    }
  
    return 0;
}
38 eps

正解:枚举a和b的差,a只有d种选择是一件奇妙的事,如果从1开始找a把不满足条件的b跳过是62分。

这个a和b恰好和题面上的换了个位置……

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = -2;
const int N = 60;
const ll mod = 1e9 + 7;

int T;
ll n, sz;
vector<pair<ll, ll> > ans;

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

inline bool check(ll l, ll r)
{
    ll res = 1;
    for(ll i=l; i<=r; i++)
    {
        res *= i;
        if(res < 0) return 0;
    }
    if(res != n) return 0;
    return 1;
}

int main()
{
    //freopen("factorial2.in", "r", stdin);
    //freopen("ww.txt", "r", stdin);
    T = read();
    while(T--)
    {
        n = read();
        ans.clear();
        //yin.clear();
        if(n == 1)
        {
            printf("-1\n"); continue;
        }
        ans.push_back(make_pair(n, n-1));
        for(int d=2; d<=20; d++)
        {
            ll Max = pow(n, 1.0/d);
            //printf("Max = %lld\n", Max);
            for(ll a=max(Max-d,1ll),b=a+d; a<=Max; a++,b++)
            {
                //printf("pair: %lld %lld\n", b, a);
                if(check(a+1, b)) ans.push_back(make_pair(b, a));
            }
        }
        sort(ans.begin(), ans.end());
        sz = ans.size();
        printf("%lld\n", sz);
        for(ll i=0; i<sz; i++)
        {
            printf("%lld %lld\n", ans[i].first, ans[i].second);
        }
    }
  
    return 0;
}
View Code

 

B. 子集

几乎每个点的开头都是一个n=1,k=1!?真是够坑的,特判n=k输出No会挂不少分。

我借鉴的题解有大字提示可惜我没带眼睛……

qes1:为什么n是偶数m(表示长度m=n/k)是奇数时无解?

把n = m * k带入求和公式——sum = (1+m*k)*m*k / 2; 如果有解要求sum是k的倍数,这样每个组的和为(i+m*k)*m / 2. n = m*k是偶数m是奇数,所以分子是奇数,然后它除不尽了。

qes2:还是直接CV好了**%%%雪域亡魂

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 1e6 + 2;
const int N = 60;
const ll mod = 1e9 + 7;

int T, n, k, m, p;
vector<int> a[maxn];

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

int main()
{
    T = read();
    while(T--)
    {
        n = read(); k = read();
        if(n == k && n != 1)
        {
            printf("No\n"); continue;
        }
        if(k == 1)
        {
            printf("Yes\n");
            for(int i=1; i<=n; i++)
            {
                printf("%d ", i);
            }
            printf("\n");
            continue;
        }
        m = n / k; 
        if(!(n & 1))
        {
            if(m & 1) 
            {
                printf("No\n"); continue;
            }
            printf("Yes\n");
            int l = 1, r = n;
            while(l < r)
            {
                int cnt = 0;
                while(cnt != m)
                {
                    printf("%d %d ", l, r); cnt += 2;
                    l++; r--;
                }
                printf("\n");
            }
        }
        else 
        {
            printf("Yes\n");
            int tmp = 0, mid = (1 + k) >> 1;
            for(int i=1; i<=k; i++)
            {
                tmp++;
                a[i].push_back(tmp);
            }
            for(int i=mid+1; i<=k; i++)
            {
                tmp++;
                a[i].push_back(tmp);
            }
            for(int i=1; i<=mid; i++)
            {
                tmp++;
                a[i].push_back(tmp);
            }
            tmp++; a[mid].push_back(tmp);
            int tot = 0;
            for(int i=0; i<=2; i++) tot += a[mid][i];
            for(int i=1; i<=k; i++)
            {
                if(i != mid) a[i].push_back(tot-a[i][0]-a[i][1]);
            }
            tmp = 3*k;
            for(int i=4; i<=m; i++)
            {
                if(i & 1)
                {
                    for(int j=1; j<=k; j++)
                    {
                        tmp++; a[j].push_back(tmp);
                    }
                }
                else 
                {
                    for(int j=k; j>=1; j--)
                    {
                        tmp++; a[j].push_back(tmp);
                    }
                }
            }
            for(int i=1; i<=k; i++)
            {
                for(int j=0; j<m; j++)
                {
                    printf("%d ", a[i][j]);
                }
                printf("\n");
            }
            for(int i=1; i<=k; i++)
            {
                a[i].clear();
            }
        }
    }
  
    return 0;
}
View Code

 

C. 混凝土粉末

非常不良心,我开了一个vector并循环模拟往上堆粉末,开大了MLE,开小了RE,总之就都是0000

转化1:做若干次区间加,询问x位置上最早>=y的时间。

为了检验一下我的rp,就去鹤了一下那个(80~100)不等的主席树,结果Copy怎么可能比原版还多呢MLE95,%%%Chen_jr

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 1e6 + 2;
const int N = 60;
const ll mod = 1e9 + 7;

int n, q, root[maxn], tot;

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

struct tree
{
    struct node 
    {
        int l, r; ll val;
    }t[maxn*40];
    int cnt;
    void insert(int &x, int hrt, int l, int r, int L, int R, ll hi)
    {
        if(!x) x = ++cnt, t[x] = t[hrt];
        if(L <= l && r <= R)
        {
            t[x].val += hi;
            return;
        }
        int mid = (l + r) >> 1;
        if(L <= mid)
        {
            t[x].l = 0;
            insert(t[x].l, t[hrt].l, l, mid, L, R, hi);
        }
        if(R > mid)
        {
            t[x].r = 0;
            insert(t[x].r, t[hrt].r, mid+1, r, L, R, hi);
        }
    }
    ll query(int x, int l, int r, int pos)
    {
        if(!x) return 0;
        if(l == r) return t[x].val;
        int mid = (l + r) >> 1;
        if(pos <= mid) return t[x].val + query(t[x].l, l, mid, pos);
        else return t[x].val + query(t[x].r, mid+1, r, pos);
    }
}t;

inline int solve(int r)
{
    int x = read(), l = 1; ll y = read();
    if(t.query(root[r], 1, n, x) < y) return 0;
    while(l < r)
    {
        int mid = (l + r) >> 1;
        if(t.query(root[mid], 1, n, x) >= y) r = mid;
        else l = mid + 1;
    }
    return l;
}

int main()
{
    //freopen("concrete2.in", "r", stdin);
    n = read(); q = read();
    for(int i=1; i<=q; i++)
    {
        int tp = read();
        if(tp == 1)
        {
            int l = read(), r = read(); ll h = read();
            t.insert(root[i], root[i-1], 1, n, l, r, h);
        }
        else 
        {
            root[i] = root[i-1];
            printf("%d\n", solve(i));
        }
    }
  
    return 0;
}
MLE 95

转化2:离线问题,把每个位置单独考虑,对于这个位置上的问题就在当前位置上二分,少了一堆多余存储。为了从一个位置走到另一个位置,可以把区间修改的贡献写成先加后减的形式。

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 1e6 + 2;
const int N = 60;
const ll mod = 1e9 + 7;

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

int n, q, ans[maxn];
bool flag[maxn];

struct node 
{
    int time; ll val;
};
vector<node> modify[maxn], query[maxn];

struct tree
{
    ll t[maxn];
    int lowbit(int x) {return x & -x; }
    void add(int x, ll h)
    {
        while(x <= q)
        {
            t[x] += h;
            x += lowbit(x);
        }
    }
    ll query(int x)
    {
        ll ans = 0;
        while(x)
        {
            ans += t[x];
            x -= lowbit(x);
        }
        return ans;
    }
}t;

int solve(node x)
{
    if(t.query(x.time) < x.val) return 0;
    int l = 1, r = x.time;
    while(l < r)
    {
        int mid = (l + r) >> 1;
        if(t.query(mid) >= x.val) r = mid;
        else l = mid + 1;
    }
    return l;
}

int main()
{
    //freopen("concrete2.in", "r", stdin);
    n = read(); q = read();
    for(int i=1; i<=q; i++)
    {
        int tp = read();
        if(tp == 1)
        {
            int l = read(), r = read(); ll h = read();
            modify[l].push_back({i, h});
            modify[r+1].push_back({i, -h});
        }
        else 
        {
            int x = read();
            query[x].push_back({i, read()});
            flag[i] = 1;
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(node x : modify[i]) t.add(x.time, x.val);
        for(node x : query[i]) ans[x.time] = solve(x);
    }
    for(int i=1; i<=q; i++)
    {
        if(flag[i])
        {
            printf("%d\n", ans[i]);
        }
    }
  
    return 0;
}
View Code

 

D. 排水系统

暴力只搞到了13分这么个不整齐的数字,它有错的所以借鉴意义不大,犹豫了一下还是不放了。

Chen_jr写得太好了言简意赅思路清晰...(Words failed me. The last few minutes saw me wolfing down his code as if it was the best food in the world. My heart was filled with excitement.)以至于我又有点lazy

至于对其它边流量影响的那个式子,就是用g[x][0] / (cd[x]-1) - g[x][0] / cd[x] 通分化简即可,我居然还看了半天没看懂***

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 2e5 + 6;
const int N = 5e5 + 2;
const ll mod = 998244353;

int n, m, r, k, inv, g[maxn][2], cd[maxn], iv[N], rd[maxn];
queue<int> q;

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

ll qpow(ll a, ll b)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

struct node 
{
    int next, to, val;
}a[N];
int head[maxn], len;

void add(int x, int y, int w)
{
    a[++len].to = y; a[len].next = head[x]; a[len].val = w;
    head[x] = len;
}

int main()
{
    n = read(); m = read(); r = read(); k = read();
    iv[1] = 1;
    for(int i=2; i<=k; i++) iv[i] = 1ll*(mod-mod/i)*iv[mod%i]%mod;
    int suma = 0;
    for(int i=1; i<=k; i++)
    {
        int u = read(), v = read(), w = read();
        add(u, v, w); suma = (suma + w) % mod;
        rd[v]++; cd[u]++;
    }
    inv = qpow(suma, mod-2);
    for(int i=1; i<=n; i++) if(!rd[i]) q.push(i);
    for(int i=1; i<=m; i++) g[i][0] = 1, g[i][1] = 1;
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        int sum = 0;
        for(int i=head[x]; i; i=a[i].next)
        {
            int v = a[i].to;
            rd[v]--; if(rd[v] == 0) q.push(v);
            g[v][1] = (g[v][1]+1ll*g[x][1]*iv[cd[x]]%mod)%mod;
            g[v][0] = (g[v][0]+1ll*g[x][0]*iv[cd[x]]%mod)%mod;
            sum = (sum+1ll*g[x][0]*inv%mod*a[i].val%mod*iv[cd[x]-1]%mod*iv[cd[x]])%mod;
        }
        for(int i=head[x]; i; i=a[i].next)
        {
            int v = a[i].to;
            g[v][1] = (g[v][1]+sum-1ll*g[x][0]*inv%mod*a[i].val%mod*iv[cd[x]-1]%mod*iv[cd[x]]%mod+mod)%mod;
            g[v][1] = (g[v][1]+mod-1ll*g[x][0]*inv%mod*a[i].val%mod*iv[cd[x]]%mod)%mod;
        }
    }
    for(int i=n-r+1; i<=n; i++) 
    {
        printf("%d ", g[i][1]);
    }
  
    return 0;
}
View Code

 

posted @ 2022-09-04 20:14  Catherine_leah  阅读(62)  评论(1编辑  收藏  举报
/* */