其他分享
首页 > 其他分享> > 2019四川省赛——解题报告(A,B,G,H,I,J)

2019四川省赛——解题报告(A,B,G,H,I,J)

作者:互联网

oj: 链接

2021/3/10 训练赛

A. Autochess

oj: 链接

题解

题意有点难懂,不过还能理解,而且还有点坑。
读懂题后,发现最难维护的点在于怎么快速找到最左边空着的位置。
我们的做法是二分+树状数组维护,同时用 m a p map map维护每个字符串的所有位置
树状数组维护非空位置的个数,这样就可以二分出最左边空着的位置,
然后再根据当前插入的字符串模拟并维护 m a p map map和树状数组即可。
其实想法不是特别难,不过题意有点坑,(所幸队友没被坑到。。)

代码

#include <bits/stdc++.h>
#define m_p make_pair
#define _for(i, a) for(int i = 0, len = (a); i < len; ++i)
#define _rep(i, a, b) for(int i = (a), len = (b); i <= len; ++i)
#define outval(a) cout << "debuging|" << #a << ":" << a << "\n";
#define dg if(debug)
#define sc(x) scanf("%d", &x)
#define scl(x) scanf("%lld", &x)
#define mem0(x) memset(x, 0, sizeof(x))
#define lowbit(x) (x & (-x))
using namespace std;
int debug = 0;
const int maxn = 100005;
const int inf = 0x3f3f3f3f;
typedef long long LL;

inline 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 n, m, k;
string s;
map< string, vector<int> > mp;
vector<string> ans;

int dat[maxn];
void insert(int p, int x) {
    while(p <= m) {
        dat[p] += x;
        p += lowbit(p);
    }
}
int query(int p) {
    int ans = 0;
    while(p) {
        ans += dat[p];
        p -= lowbit(p);
    }
    return ans;
}

int leftmost() {
    int l = 1, r = m, ans = m + 1;
    while(l <= r) {
        int mid = (l + r) >> 1;
        int tem = query(mid);
        if(query(mid) < mid) {
            ans = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
    return ans;
}

void init() {
    mem0(dat);
    mp.clear();
    ans.resize(m + 1);
    _rep(i, 1, m) ans[i] = "";
    _rep(i, 1, m) dat[i] = 0;
}

int sol(int ttt) {
    init();
    int np = 0;
    _rep(i, 1, n) {
        string s;
        cin >> s;
        if(mp.count(s + "3")) continue;
        if((mp[s].size() + 1) % k && np == m) continue;
        int t = leftmost();
        // if(t > m) continue;
        insert(t, 1);
        mp[s].push_back(t);
        ++np;
        if(mp[s].size() == k) {
            dg {
                cout << "s:" << s << "\tpos:";
                for(auto i : mp[s]) cout << " " << i;
                cout << "\n";
            }
            for(int i : mp[s]) insert(i, -1);
            mp.erase(mp.find(s));
            np -= k - 1;
            int t = leftmost();
            insert(t, 1);
            s.push_back('2');
            mp[s].push_back(t);
            if(mp[s].size() == k) {
                for(int i : mp[s]) insert(i, -1);
                mp.erase(mp.find(s));
                np -= k - 1;
                s[s.size() - 1] = '3';
                int t = leftmost();
                insert(t, 1);
                mp[s].push_back(t);
            }
        }
    }
    cout << "Case " << ttt << ":";
    for(auto i : mp) {
        for(int j : i.second) {
            ans[j] = i.first;
        }
    }
    _rep(i, 1, m) {
        if(ans[i].size() != 0) {
            cout << " " << ans[i];
        }
        else cout << " -1";
    }
    cout << "\n";
    return 0;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    // debug = 1;
#endif
    int T;
    cin >> T;
    _for(i, T) {
        cin >> n >> m >> k;
        sol(i + 1);
    }
    return 0;
}

B. Bin Packing

oj: 链接

题解

直接暴力枚举四种情况维护答案即可。
1.两个都竖着
2.两个都横着
3.一个横着一个竖着(两种情况)

代码

#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 = 1e5+7;
double calc(int x1,int y1,int x2,int y2){
    double ans=x1*y1+x2*y2;
    if(y1>y2) ans+=(y1-y2)*x2*1.0/2;
    else ans+=(y2-y1)*x1*1.0/2;
    return ans;
}
int kcase=0;
void solve(){
    int w1=read(),h1=read();
    int w2=read(),h2=read();
    double ans1=min(calc(w1,h1,w2,h2),calc(w1,h1,h2,w2));
    double ans2=min(calc(h1,w1,w2,h2),calc(h1,w1,h2,w2));
    printf("Case %d: %.6f\n",++kcase,min(ans1,ans2));
}
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. Game of Primes

oj: 链接

题解

感觉还算不是特别难想的博弈,而且也是挺经典的博弈思路。
首先把初始就能分出胜负的情况特判处理。
然后我们先考虑 B o b Bob Bob先手的情况:
当 ( x , y ) (x,y) (x,y)可以分解为 ( p 1 + t , p 2 + t ) { p 1 ∈ P r i m e , p 2 ∈ P r i m e } (p1+t,p2+t)\{p1\in Prime,p2\in Prime\} (p1+t,p2+t){p1∈Prime,p2∈Prime},且 p 1 > k , p 2 > k p1>k,p2>k p1>k,p2>k时, A l i c e Alice Alice必胜。
否则 B o b Bob Bob必胜。
原因:
每当 B o b Bob Bob选择减 x x x时, A l i c e Alice Alice就选择减 y y y,
这样最后肯定是到 A l i c e Alice Alice必胜的条件。
然后我们考虑 A l i c e Alice Alice先手的情况,因为我们已经知道 A l i c e Alice Alice必胜的条件了,而且 A l i c e Alice Alice先手后紧接着就是 B o b Bob Bob先手了,即满足第一种情况。
那么我们只需要判断 A l i c e Alice Alice先手后的两种状态是否符合第一种情况,有的话 A l i c e Alice Alice肯定选择这种状态,因为这样能保证自己必胜。

代码

#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 pA puts("Alice")
#define pB puts("Bob")
#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;
}
struct Prime {
    vector<int> arr;
    int vis[1000006];
    void doit(int maxnum) {
        for(int i = 2; i <= maxnum; ++i) {
            if(!vis[i]) arr.push_back(i);
            for(int j = 0; j < arr.size() && arr[j] * i <= maxnum; ++j) {
                vis[arr[j] * i] = 1;
                if(i % arr[j] == 0) break;
            }
        }
    }
}P;
int x,y,k,w;
int check(int xx,int yy){
    if(xx==k||yy==k) return 0;
    if(!P.vis[xx]&&!P.vis[yy]) return 1;
    rp(i,1,min(xx,yy))
        if(xx-i>k&&yy-i>k&&!P.vis[xx-i]&&!P.vis[yy-i])
            return 1;
    return 0;
}
int kcase=0;
void solve(){
    x=read(),y=read(),k=read(),w=read();
    cout<<"Case "<<++kcase<<": ";
    if(!P.vis[x]&&!P.vis[y]&&x!=k&&y!=k){
        pA;
        return ;
    }
    if(x==k||y==k){
        pB;
        return ;
    }
    if(!w){  
        // outval2(check(x-1,y),check(x,y-1));
        if(check(x-1,y)||check(x,y-1)) pA;
        else pB;
    }
    else{
        if(check(x,y)) pA;
        else pB;
    }
}
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();
    P.doit(1000007);
    int T=read();
    while(T--) solve();

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

H. Hack a Contest

oj: 链接

题解

简单贪心题,直接按照每个问题的提交次数从大到小枚举,同时提交时间按照从大到小贪心取即可。

代码

#include <bits/stdc++.h>
#define m_p make_pair
#define _for(i, a) for(int i = 0, len = (a); i < len; ++i)
#define _rep(i, a, b) for(int i = (a), len = (b); i <= len; ++i)
#define outval(a) cout << "debuging|" << #a << ":" << a << "\n";
#define dg if(debug)
#define sc(x) scanf("%d", &x)
#define scl(x) scanf("%lld", &x)
using namespace std;
int debug = 0;
const int inf = 0x3f3f3f3f;
typedef long long LL;

inline 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{

};
const int N = 1e5+7;
int t[N],c[N];
int tt=1;
void sol() {
    int n=read(),m=read();
    _rep(i,1,n) t[i]=read();
    sort(t+1,t+1+n,greater<int>());
    _rep(i,1,m) c[i]=read();
    sort(c+1,c+1+m,greater<int>());
    LL ans=0;
    int cur=1;
    _rep(i,1,m){
        ans+=t[cur]+1ll*20*(c[i]-1);
        cur+=c[i];
    }
    cout<<"Case "<<tt++<<": "<<ans<<endl;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    debug = 1;
#endif
    int T=read();
    while(T--){
        sol();
    }
    return 0;
}

I. Inventory

oj: 链接

题解

柯西不等式的模板题,
当然现场可能想不到,不过猜结论可能能够猜到。
这里提供一个猜结论的思路
第一个样例不好猜,我们考虑对第二个样例分析。
因为只有两个数都很小,所以我们可以考虑暴力枚举出接近正确答案的 v 1 , v 2 v_{1},v_{2} v1​,v2​。
近似得出 v 1 = 0.666666 , v 2 = 1.333333 v_{1}=0.666666,v_{2}=1.333333 v1​=0.666666,v2​=1.333333。
可以发现 v 1 : v 2 = 1 : 2 v_{1}:v_{2}=1:2 v1​:v2​=1:2。
然后我们考虑给的 x 1 = 2 , x 2 = 8 x_{1}=2,x_{2}=8 x1​=2,x2​=8。
什么情况下通过这两个数的运算能够得到 1 : 2 1:2 1:2这个比值呢。
不难想到开根号刚好能够得出。
因此我们就构造出了这个样例,直接按照我们的这个思路( v v v数组的比值等于 x x x数组每个元素开根号的比值)莽一发就行了。
证明(一般形式的柯西不等式):
在这里插入图片描述

代码

#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 = 1e5+7;
int a[N];
int t;
void solve(){
    int n=read(),V=read();
    double ans=0;
    rp(i,1,n){
        a[i]=read();
        ans+=sqrt(a[i]);
    }
    ans=ans*ans;
    printf("Case %d: %.6f\n",++t,ans/V);
}
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;
}

J. Jump on Axis

oj: 链接

题解

我们先预处理出三种选择的前缀和,可以发现到 3000 3000 3000之后就大于 10000000 10000000 10000000了,因此我们直接暴力枚举第一种选择的和以及第二种选择的和,二分去找第三种选择的和即可。
我分了三种情况来处理:
1.有一种选择构成
2.有两种选择构成
3.有三种选择构成
最小步数不难维护,关键在于方案数,需要排列组合计算出来。
这里举有两个选择构成的例子:
假设一种选择有 x x x个数,另一种选择有 y y y个数,且这两个选择的所有数的和等于 k k k,那么方案数就是 C x + y x C_{x+y}^{x} Cx+yx​。
三种选择的情况类推一下即可。

代码

#include <bits/stdc++.h>
#define m_p make_pair
#define _for(i, a) for(int i = 0, len = (a); i < len; ++i)
#define _rep(i, a, b) for(int i = (a), len = (b); i <= len; ++i)
#define outval(a) cout << "debuging|" << #a << ":" << a << "\n";
#define dg if(debug)
#define sc(x) scanf("%d", &x)
#define scl(x) scanf("%lld", &x)
#define mem0(x) memset(x, 0, sizeof(x))
#define lowbit(x) (x & (-x))
using namespace std;
int debug = 0;
const int maxn = 100005;
const int inf = 0x3f3f3f3f;
typedef long long LL;

inline 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{

};
const int N = 1e5+7;
const LL mod = 1e9+7;
int a1[N],a2[N],a3[N];
LL sum1[N],sum2[N],sum3[N];
vector<LL> s1,s2,s3;
LL fac[N];
void init(){
    a1[1]=1;
    _rep(i,2,N-7) a1[i]=a1[i-1]+3; 
    a2[1]=2;
    _rep(i,2,N-7) a2[i]=a2[i-1]+3; 
    a3[1]=3;
    _rep(i,2,N-7) a3[i]=a3[i-1]+3; 

    _rep(i,1,N-7){
        sum1[i]=sum1[i-1]+a1[i];
        if(sum1[i]>10000000) break;
        s1.push_back(sum1[i]);
    }
    _rep(i,1,N-7){
        sum2[i]=sum2[i-1]+a2[i];
        if(sum2[i]>10000000) break;
        s2.push_back(sum2[i]);
    }
    _rep(i,1,N-7){
        sum3[i]=sum3[i-1]+a3[i];
        if(sum3[i]>10000000) break;
        s3.push_back(sum3[i]);
    }
    fac[0]=1;
    _rep(i,1,N-7) fac[i]=(fac[i-1]*i)%mod;

}
LL quick_pow(LL a,LL b){
    LL res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return res;
}
LL inv(LL x){
    return quick_pow(x,mod-2)%mod;
}
LL C(int n,int m){
    return fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod;
}
LL calc2(LL a,LL b){
    return C(a+b,a)%mod;
}
LL calc3(LL a,LL b,LL c){
    return C(a+b,a)*C(a+b+c,c)%mod;
}
void sol(int ttt) {
    int K=read();
    LL res1=inf;
    LL res2=0;
    LL num1=0;
    int len1=s1.size(),len2=s2.size(),len3=s3.size();
    //只有一个
    int id=lower_bound(s1.begin(),s1.end(),K)-s1.begin();
    if(id<len1&&s1[id]==K){num1++;res1=min(res1,1LL*(id+1));}

    id=lower_bound(s2.begin(),s2.end(),K)-s2.begin();
    if(id<len2&&s2[id]==K){num1++;res1=min(res1,1LL*(id+1));}

    id=lower_bound(s3.begin(),s3.end(),K)-s3.begin();
    if(id<len3&&s3[id]==K){num1++;res1=min(res1,1LL*(id+1));}
    res2=(num1+res2)%mod;
    if(debug) cout<<num1<<endl;

    LL num2=0;
    //只有两个
    //1,2
    _rep(i,1,K){
        if(sum1[i]>=K) break;
        LL temp=K-sum1[i];
        int idd=lower_bound(s2.begin(),s2.end(),temp)-s2.begin();
        if(idd<len2&&s2[idd]==temp){
            num2=(num2+calc2(i,idd+1))%mod;
            res1=min(res1,1LL*(i+(idd+1)));
        }   
    }
    //1,3
    _rep(i,1,K){
        if(sum1[i]>=K) break;
        LL temp=K-sum1[i];
        int idd=lower_bound(s3.begin(),s3.end(),temp)-s3.begin();
        if(idd<len3&&s3[idd]==temp){
            num2=(num2+calc2(i,idd+1))%mod;
            res1=min(res1,1LL*(i+(idd+1)));
        }   
    }
    //2,3
     _rep(i,1,K){
        if(sum2[i]>=K) break;
        LL temp=K-sum2[i];
        int idd=lower_bound(s3.begin(),s3.end(),temp)-s3.begin();
        if(idd<len3&&s3[idd]==temp){
            num2=(num2+calc2(i,idd+1))%mod;
            res1=min(res1,1LL*(i+(idd+1)));
        }   
    }
    res2=(res2+num2)%mod;
    if(debug) cout<<num2<<endl;
    //有三个
    LL num3=0;
    _rep(i,1,K){
        if(sum1[i]>=K) break;
        _rep(j,1,K){
            if(sum2[j]>=K-sum1[i]) break;
            LL temp=K-sum1[i]-sum2[j];
            int idd=lower_bound(s3.begin(),s3.end(),temp)-s3.begin();
            if(idd<len3&&s3[idd]==temp){
                // dg cout<<i<<" "<<j<<" "<<idd<<endl;
                num3=(num3+calc3(i,j,idd+1))%mod;
                res1=min(res1,1LL*(i+j+(idd+1)));
            }  
        }
    }
    dg cout<<num3<<endl;
    res2=(res2+num3)%mod;
    cout<<"Case "<<ttt<<": "<<res1<<" "<<res2<<endl;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    // debug = 1;
#endif
    init();
    int T=read();
    _rep(i,1,T) {
        sol(i);
    }
    return 0;
}

标签:ch,return,四川省,int,LL,read,解题,2019,define
来源: https://blog.csdn.net/qq_43472263/article/details/114788001