The 15th Heilongjiang Provincial Collegiate Programming Contest(A,C,F,G,H,L)

比赛链接

2021/2/7训练赛

Problem.A August

题解

不难发现上半部分是个半径为 a a a的圆,下半部分利用割补小正方形的方法得出等价于一个长为 2 a 2a 2a,宽为 2 b 2b 2b的长方形。
比赛时没有发现,不过队友看出下半部分面积应该是个关于 a a a b b b的表达式,并且很好算,用答案减去圆的面积反推出面积为 4 a b 4ab 4ab

代码

#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;
}
void solve(){
    int a=read(),b=read();
    double ans=PI*a*a;
    printf("%.8f\n",ans+4.0*a*b);
}
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;
}

Problem.C Cornelia Street

题解

比赛时感觉时间复杂度不是特别好确定,而且极端数据不是特别好构造,就写了一法暴力枚举 A A A串长度的做法,交之前测了几发大数据都过了,就交了,一发A。
时间复杂度好像类似于调和级数。

代码

#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;
void solve(){
    string s;cin>>s;
    int len=s.size();
    rp(l,1,len){
        string pa="";
        rp(i,0,l-1) pa+=s[i];
        string pb="";
        int f=1;
        int ff=0;
        rp(i,l,len-1){
            int num=1;
            string t="";t+=s[i];
            while(i+1<len&&num<l) i++,t+=s[i],num++;
            if(t==pa){
                if(f==2) f=3;
            }
            else if(pb.size()==0&&f==1){
                pb=t;f=2;
            }
            else if(t==pb&&f==2) continue;
            else {
                if(f==3){
                    if(i==len-1){
                        string tt=pa.substr(0,num);
                        if(tt!=t){
                            ff=1;
                            break;
                        }
                    }
                    else{
                        ff=1;
                        break;
                    }
                }
                else{
                    ff=1;
                    break;
                }
            }
        }
        // outval2(l,ff);
        if(!ff&&f!=1){
            cout<<pa<<" "<<pb<<endl;
            break;
        }
    }
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);

    solve();
    return 0;
}

Problem.F False God

队友写的:
请参考题解

Problem.G Goodbye

题解

手推几个样例可以发现规律:
首先对 n n n进行唯一分解,并维护出最大的两个质因子。
1.当 n n n为质数或者 1 1 1时,输出 0 0 0
2.当质因子个数小于等于2时,输出 − 1 -1 1
3.否则答案就是这两个最大的质因子的乘积。
原因:首先为了保证 C h i n o Chino Chino必胜,只能给 D a v i d David David剩下两个质因子的乘积。
而又需要保证 C h i n o Chino Chino的第一轮取的值最大,根据贪心的原则选取最大的两个质因子的乘积是最优策略。

代码

// #pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 100005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;

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 * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

struct poi {

};

int n;

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;
        }
    }
}

void init() {

}

void sol() {
    init();
    if(n == 1) {
        printf("0\n");
        return;
    }
    int a = 0, b = 0;
    int x = n;
    for(int i = 0; i < arr.size() && arr[i] <= x; ++i) {
        // dg outval(arr[i]);
        while(x % arr[i] == 0) {
            if(arr[i] > a) {
                b = a;
                a = arr[i];
            }
            else if(arr[i] > b) b = arr[i];
            x /= arr[i];
        }
    }
    if(a == n) {
        printf("0\n");
        return;
    }
    if(b == 0 || n == a * b) {
        printf("-1\n");
        return;
    }
    // dg outval(a), outval(b);
    printf("%d\n", a * b);
}

int main() {
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    debug = 1;
#endif
    time_t beg, end;
    if(debug) beg = clock();

    doit(100000);
    int T = read();
    _for(i, T) {
        n = read();
        sol();
    }
    // _rep(i, 1, 20) {
    //     n = i;
    //     sol();
    // }

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

Problem.H Hate That You Know Me

题解

这个题首先需要知道两个结论:
1.约数个数和等于数论分块和
∑ i = 1 n σ 0 ( i ) = ∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^n\sigma_0(i)=\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor i=1nσ0(i)=i=1nin
2.约数和等于数论分块和的变形
∑ i = 1 n σ 1 ( i ) = ∑ i = 1 n i × ⌊ n i ⌋ \sum_{i=1}^n\sigma_1(i)=\sum_{i=1}^ni\times\lfloor\frac{n}{i}\rfloor i=1nσ1(i)=i=1ni×in
那么我们不难得出约数平方和以及约数立方和的公式:
约数平方和
∑ i = 1 n σ 2 ( i ) = ∑ i = 1 n i 2 × ⌊ n i ⌋ \sum_{i=1}^n\sigma_2(i)=\sum_{i=1}^ni^{2}\times\lfloor\frac{n}{i}\rfloor i=1nσ2(i)=i=1ni2×in
约数立方和
∑ i = 1 n σ 3 ( i ) = ∑ i = 1 n i 3 × ⌊ n i ⌋ \sum_{i=1}^n\sigma_3(i)=\sum_{i=1}^ni^{3}\times\lfloor\frac{n}{i}\rfloor i=1nσ3(i)=i=1ni3×in
那么把公式转换以后不难发现第二个公式可以直接用数论分块求出答案。
对数论分块不懂的话请参考该链接
题目中给的取余是自然溢出,我们直接用unsigned long long 维护答案即可。

trick: 注意要保证能够整除再进行除运算,否则直接用下取整会使得答案偏小。

代码

#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 ll 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;
}
ll f1(ll x){
    ll a=x,b=x+1;
    if(a%2==0) a/=2;
    else b/=2;
    return a*b;
}
ll f2(ll x){
    ll a=x,b=x+1,c=2*x+1;
    if(a%2==0) a/=2;
    else b/=2;
    if(a%3==0) a/=3;
    else if(b%3==0) b/=3;
    else if(c%3==0) c/=3;
    return a*b*c;
}
ll f3(ll x){
    ll a=x,b=x+1;
    if(a%2==0) a/=2;
    else b/=2;
    return a*b*a*b;    
}
ll calc(ll l,ll r,ll op){
    if(op==0) return r-l+1ll;
    else if(op==1) return f1(r)-f1(l-1); 
    else if(op==2) return f2(r)-f2(l-1);
    else return f3(r)-f3(l-1);
}
void solve(){
    ll a,b,n;cin>>a>>b>>n;
    if(a==b){
        puts("0");
        return ;
    }
    ll ans1=0;
    for(ll l = 1, r = 0; l <= n; l=r+1) {
        r = n / (n / l);
        ans1+=(n/l)*calc(l,r,a);
    }
    ll ans2=0;
    for(ll l = 1, r = 0; l <= n; l=r+1) {
        r = n / (n / l);
        ans2+=(n/l)*calc(l,r,b);
        // outval3(l,r,calc(l,r,b));
    }   
    // outval2(ans1,ans2);
    cout<<(ans1^ans2)<<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=1;
    while(T--) solve();

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

Problem.L Let’s Get Married

题解

可以发现是按照 b f s bfs bfs的顺序进行放的。
那么我们对于每次的 1 1 1操作,二分枚举得出 i d id id的层数,并可以找规律得出具体坐标。
对于每次的 2 2 2操作,也可以通过找规律得出其编号。

代码

// #pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<LL, LL>
#define _for(i, a) for(LL i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(LL i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
// #define scl(x) scanf("%lld", &x)
// #define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const LL maxn = 100005;
const LL maxm = 1000005;
const LL maxp = 30;
const LL inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
LL debug = 0;

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 * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

LL n;

inline void print(LL x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}

pair< LL, LL > getV(LL id) {
    if(id <= 4) return m_p(0, 0);
    LL l = 1, r = 1e9, ans = l;
    while(l <= r) {
        LL mid = (l + r) /2;
        if((4 * mid + 4) * mid / 2 <= id) {
            ans = mid;
            l = mid + 1;
        }
        else r = mid - 1;
    }
    return m_p(ans, (4 * ans + 4) * ans / 2);
}

int main() {
    // ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    // debug = 1;
#endif
    n = read();
    LL nx = 0, ny = 0;
    _for(i, n) {
        LL op = read(), x, y;
        if(op == 1) {
            LL id = read();
            if(id == 0) {
                x = 0, y = 0;
            }
            else {
                pair<LL, LL> t = getV(id);
                dg outval(t.first), outval(t.second);
                if(id - t.second <= 2 * t.first + 1) {
                    if((id - t.second) == 0) {
                        x = 0, y = t.first + 1;
                    }
                    else if((id - t.second)%2==1LL) {
                        x = -(id - t.second) / 2, y = t.first + 1 - (id - t.second) / 2;
                    }
                    else {
                        x = (id - t.second) / 2, y = t.first + 1 - (id - t.second) / 2;
                    }
                }
                else if((id - t.second) <= 2 * t.first + 1 + t.first + 2) {
                    LL nol = t.second + 2 * t.first + 2;
                    x = t.first + 1 - (id - nol), y = -(id - nol);
                }
                else {
                    LL nod = t.second + 2 * t.first + 2 + t.first + 1;
                    x = -(id - nod), y = -(t.first + 1 - (id - nod));
                }
            }
            dg printf("x:%lld\ty:%lld\n", x, y);
            print(x - nx);
            printf(" ");
            print(y - ny);
            printf("\n");
        }
        else {
            x = read(), y = read();
            if(x == 0 && y == 0) {
                printf("0\n");
            }
            else {
                LL tf = abs(x) + abs(y) - 1;
                LL ts = (4 * tf + 4) * tf / 2;
                if(x == 0 && y > 0) print(ts + 1), printf("\n");
                else if(x > 0 && y > 0) {
                    print(ts + 2 * x); printf("\n");
                }
                else if(x < 0 && y > 0) {
                    print(ts + 1 - 2 * x); printf("\n");
                }
                else if(x >= 0 && y <= 0) {
                    LL nol = ts + 2 * tf + 2;
                    print(nol - y); printf("\n");
                }
                else {
                    LL nod = ts + 2 * tf + 2 + tf + 1;
                    print(nod - x); printf("\n");
                }
            }
        }
        nx = x, ny = y;
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值