2018-2019 ICPC, NEERC, Northern Eurasia Finals(F,K)

ICPC竞赛算法解析
本文深入解析了2018-2019年度ICPC NEERC Northern Eurasia Finals中的两道难题,分别是Fractions和King Kog's Reception。通过巧妙的数学推导和数据结构应用,展示了如何解决涉及分数分解和区间查询的复杂问题。

2018-2019 ICPC, NEERC, Northern Eurasia Finals

在此附上题解

Problem F:Fractions
思路:看懂题意之后,相当于求解 x 1 n + x 2 n + x 3 n + ⋯ + x k n = n − 1 n \frac {x_1}{n}+\frac {x_2}{n}+\frac {x_3}{n}+\dots +\frac {x_k}{n}=\frac {n-1}{n} nx1+nx2+nx3++nxk=nn1 其中 g c d ( x i , n ) > 1 gcd(x_i,n)>1 gcd(xi,n)>1
这下不了手,然后发现很多数只需要2项即可凑出来,大胆猜了一发。
如果只有2项的话,则是 x b + y a = n − 1 n \frac {x}{b}+\frac{y}{a}=\frac{n-1}{n} bx+ay=nn1
其中 a ∗ b = n a*b=n ab=n,然后就是求 a x + b y = n − 1 ax+by=n-1 ax+by=n1的正整数解了,用扩展欧几里德即可。

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e9+7;
const int MAX=2e5+10;
const double PI=acos(-1.0);
typedef long long ll;
ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
void exgcd(ll a,ll b,ll &x,ll&y)
{
    if(b==0){x=1;y=0;}
    else
    {
        exgcd(b,a%b,y,x);
        y-=x*(a/b);
    }
}
int main()
{
    ll n;
    cin>>n;
    for(ll i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            ll a=i;
            ll b=n/i;
            ll g=gcd(a,b);
            if((n-1)%g)continue;
            ll x,y;
            exgcd(a,b,x,y);
            x=(x+b/g)*((n-1)/g);
            x=(x%(b/g)+b/g)%(b/g);
            y=(n-1-a*x)/b;
            printf("YES\n2\n");
            printf("%lld %lld\n",x/gcd(x,b),b/gcd(x,b));
            printf("%lld %lld\n",y/gcd(y,a),a/gcd(y,a));
            return 0;
        }
    }
    puts("NO");
    return 0;
}

Problem K:King Kog’s Reception

思路:对于一个区间 [ L , R ] [L,R] [L,R]来说,假设这个区间内所有骑士的 d d d的值加起来为 s u m [ L ] [ R ] sum[L][R] sum[L][R],若 s u m [ L ] [ R ] − ( R − L ) &gt; 0 sum[L][R]-(R-L)&gt;0 sum[L][R](RL)>0,很明显,骑士最后结束见面的时间是会超出这个区间的,且超出的时间 t i m e = s u m [ L ] [ R ] − ( R − L ) time=sum[L][R]-(R-L) time=sum[L][R](RL)

那么对于每个询问 t t t,我们就是要找到最大的 t i m e time time
t i m e = m a x ( s u m [ i ] [ t ] − ( t − i ) ) time=max(sum[i][t]-(t-i)) time=max(sum[i][t](ti)) t i m e = m a x ( s u m [ i ] [ t ] + i − t ) , ( 1 ≤ i ≤ t ) time=max(sum[i][t]+i-t),(1\le i\le t) time=max(sum[i][t]+it),(1it)
然后就需要用数据结构来维护 s u m [ i ] [ t ] + i sum[i][t]+i sum[i][t]+i了。

#include<bits/stdc++.h>
using namespace std;
const int MOD=998244353;
const int MAX=1e6+10;
const double PI=acos(-1.0);
typedef long long ll;
int X[MAX],Y[MAX];
struct lenka
{
    int l,r;
    ll ma,tag;
}A[MAX<<2];
void build(int k,int l,int r)
{
    A[k].l=l,A[k].r=r;
    A[k].ma=l;
    if(l==r)return;
    build(2*k,l,(l+r)/2);
    build(2*k+1,(l+r)/2+1,r);
    A[k].ma=max(A[2*k].ma,A[2*k+1].ma);
}
void add(int k,int x,int y,ll z)
{
    if(x==A[k].l&&y==A[k].r)
    {
        A[k].tag+=z;
        A[k].ma+=z;
        return;
    }
    if(A[k].tag)
    {
        add(2*k,A[2*k].l,A[2*k].r,A[k].tag);
        add(2*k+1,A[2*k+1].l,A[2*k+1].r,A[k].tag);
        A[k].tag=0;
    }
    if(y<=A[2*k].r)add(2*k,x,y,z);
    else if(x>=A[2*k+1].l)add(2*k+1,x,y,z);
    else
    {
        add(2*k,x,A[2*k].r,z);
        add(2*k+1,A[2*k+1].l,y,z);
    }
    A[k].ma=max(A[2*k].ma,A[2*k+1].ma);
}
ll askma(int k,int x,int y)
{
    if(x==A[k].l&&y==A[k].r)return A[k].ma;
    if(A[k].tag)
    {
        add(2*k,A[2*k].l,A[2*k].r,A[k].tag);
        add(2*k+1,A[2*k+1].l,A[2*k+1].r,A[k].tag);
        A[k].tag=0;
    }
    if(y<=A[2*k].r)return askma(2*k,x,y);
    if(x>=A[2*k+1].l)return askma(2*k+1,x,y);
    return max(askma(2*k,x,A[2*k].r),askma(2*k+1,A[2*k+1].l,y));
}
ll BIT[MAX];
void add(int x,int y){while(x<=1000000){BIT[x]+=y;x+=x&(-x);}}
ll ask(int x){ll tot=0;while(x){tot+=BIT[x];x-=x&(-x);}return tot;}
int main()
{
    build(1,1,1000000);
    int T;
    cin>>T;
    for(int i=1;i<=T;i++)
    {
        char s[4];
        scanf("%s",s);
        if(s[0]=='+')
        {
            scanf("%d%d",&X[i],&Y[i]);
            add(1,1,X[i],Y[i]);
            add(X[i],Y[i]);
        }
        if(s[0]=='-')
        {
            scanf("%d",&X[i]);
            add(1,1,X[X[i]],-Y[X[i]]);
            add(X[X[i]],-Y[X[i]]);
        }
        if(s[0]=='?')
        {
            scanf("%d",&X[i]);
            printf("%lld\n",askma(1,1,X[i])-X[i]-(ask(1000000)-ask(X[i])));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值