AIsing Programming Contest 2020


A B C D E F

( √:做出; ●:尝试未做出; ○:已补题 )


题目地址:https://atcoder.jp/contests/aising2020



A Number of Multiples

题意:签到题

思路

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
    int x=0,flag=1;
    char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

int main()
{
    int L=read(),R=read(),d=read();
    int ans=0;
    REP(i,L,R) if(i%d==0) ans++;
    cout<<ans;

    return 0;
}



B An Odd Problem

题意:签到题

思路

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
    int x=0,flag=1;
    char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

int main()
{
    int ans=0,n=read();
    REP(i,1,n)
    {
        int x=read();
        if(i&1 && x&1) ans++;
    }
    cout<<ans;

    return 0;
}



C XYZ Triplets

题意 f ( n ) f(n) 表示满足以下条件的三元组 ( x , y , z ) (x,y,z) 的个数:

  • 1 x , y , z 1\le x,y,z
  • x 2 + y 2 + z 2 + x y + y z + z x = n x^2+y^2+z^2+xy+yz+zx=n

给出 N( 1 N 1 0 4 1\le N\le 10^4 ),输出 f ( 1 ) , f ( 2 ) , . . . , f ( N ) f(1),f(2),...,f(N)

思路:根据 N 的范围可以推断出,xyz都不超过100,所以就三重循环更新 f 数组就行了。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
    int x=0,flag=1;
    char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

int f[10005];

int main()
{
    REP(i,1,100) REP(j,1,100) REP(k,1,100)
    {
        int x=i*i+j*j+k*k+i*j+i*k+j*k;
        if(x<=10000) f[x]++;
    }
    int N=read();
    REP(i,1,N) printf("%d\n",f[i]);

    return 0;
}



D Anything Goes to Zero

题意 f ( n ) f(n) 表示把一个非负整数 n 经过若干次这样的操作——把 n 替换成 n   m o d   p o p c o u n t ( n ) n \ mod \ popcount(n) ——最后变成 0 所需要操作的次数。现在给出有 N( 1 N 2 × 1 0 5 1\le N\le 2\times10^5 ) 位的二进制数 X,对于每一位 1 i N 1\le i\le N ,定义 X i X_i 为把 X 的第 i 位反转变成的二进制数,求出 f ( X 1 ) , f ( X 2 ) , . . . , f ( X N ) f(X_1),f(X_2),...,f(X_N)

思路:对于每一个 X i X_i ,如果我们计算完第一步,也就是经过了一次操作之后,得到的结果一定不超过 N,因为一开始的 X 的 1 的个数不会超过 N,然后之后的操作就可以很快的完成。所以最重要的是如何尽快的把每一个 X i X_i 的第一步计算出来。设原来的 X 有 m 个 1,那么对于每个 X i X_i ,1 的个数要么是 m-1,要么是 m+1,所以我们只需要求出 X 对 m-1 和 m+1 的模,并且求出每一个 2 的幂对 m-1 和 m+1 的模,然后对于每一个 X i X_i ,只需要在 X 的答案的基础上减去或者加上相应的 2 的幂的答案就行了。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
    int x=0,flag=1;
    char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=2e5+5;
int a[maxn],M=0,n,f[maxn],ff[maxn];
LL tot,tott;
char s[maxn];

int get(int x)
{
    int ret=0;
    while(x)
    {
        ret++;
        x%=__builtin_popcount(x);
    }
    return ret;
}

int main()
{
    n=read();
    scanf("%s",s+1);
    REP(i,1,n) a[i]=s[i]-'0',M+=a[i];

    if(M==0) {REP(i,1,n) puts("1"); return 0;}
    if(M==1)
    {
        if(a[n]==1)
        {
            REP(i,1,n-1) puts("2");
            puts("0");
            return 0;
        }
        else
        {
            REP(i,1,n-1) puts(a[i]?"0":"1");
            puts("2");
            return 0;
        }
    }
    f[0]=1%(M-1); ff[0]=1%(M+1);
    REP(i,1,n) f[i]=f[i-1]*2%(M-1),ff[i]=ff[i-1]*2%(M+1);
    REP(i,1,n) if(a[i]) tot+=f[n-i],tott+=ff[n-i];

    REP(i,1,n)
    {
        int x;
        if(a[i]) x=(tot-f[n-i])%(M-1);
        else x=(tott+ff[n-i])%(M+1);
        printf("%d\n",1+get(x));
    }

    return 0;
}



E Camel Train

题意:有 n 只骆驼。对于第 i 只骆驼,给出三个正整数 K i , L i , R i K_i,L_i,R_i ,表示如果把这只骆驼放在前 K i K_i 的位置,就会有收益 L i L_i ,否则会有收益 R i R_i 。问最大收益。

思路:我们可以把骆驼分为两组: L i R i L_i\ge R_i 的(1组)和 L i < R i L_i < R_i 的(2组)。这样 1组的骆驼一定全部在 2组骆驼的左边,否则交换相应骆驼也不会使得总收益变少。我们如果满足第 i 只骆驼(这里满足的意思是指按照其 L 和 R 的大小关系给它分配收益更大的位置),实际上获得的可以跟其它骆驼比较的收益是 L i R i |L_i-R_i| 。也就是说,对于每只骆驼我们都可以看成有一个基础收益 min { L i , R i } \min\{L_i,R_i\} ,然后我们要尽量满足 L i R i |L_i-R_i| 更大的骆驼。这里就对两组骆驼分别用优先队列去维护符合要求的 L i R i |L_i-R_i| 即可。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=2e5+5;
struct node
{
    int L,R,K;
    bool operator < (const node x) const {return K<x.K;}
}a[maxn];

int main()
{
    int T=read();
    while(T--)
    {
        int n=read();
        REP(i,1,n) a[i].K=read(),a[i].L=read(),a[i].R=read();
        vector<node> x,y;
        REP(i,1,n)
            if(a[i].L>=a[i].R) x.pb(a[i]);
            else y.pb(a[i]);
        sort(x.begin(),x.end()); sort(y.begin(),y.end());
        LL ans=0;
        REP(i,1,n) ans+=min(a[i].L,a[i].R);

        priority_queue<int,VI,greater<int> > Q;
        REP(i,1,x.size())
        {
            int add=abs(x[i-1].L-x[i-1].R),k=x[i-1].K;
            if(k>Q.size()) Q.push(add);
            else if(!Q.empty() && add>Q.top()) Q.pop(),Q.push(add);
        }
        while(!Q.empty()) ans+=Q.top(),Q.pop();
        REP(i,1,y.size())
        {
            int add=abs(y[y.size()-i].L-y[y.size()-i].R),k=n-y[y.size()-i].K;
            if(k>Q.size()) Q.push(add);
            else if(!Q.empty() && add>Q.top()) Q.pop(),Q.push(add);
        }
        while(!Q.empty()) ans+=Q.top(),Q.pop();
        printf("%lld\n",ans);
    }

    return 0;
}



F Two Snuke

题意:给定一个正整数 N( 1 N 1 0 9 1\le N\le 10^9 ),要求凑出十个非负整数 s 1 , s 2 , n 1 , n 2 , u 1 , u 2 , k 1 , k 2 , e 1 , e 2 s_1,s_2,n_1,n_2,u_1,u_2,k_1,k_2,e_1,e_2 ,并且满足: 0 s 1 < s 2 0\le s_1 < s_2 (其它四组一样),且 s 1 + s 2 + n 1 + n 2 + u 1 + u 2 + k 1 + k 2 + e 1 + e 2 N s_1+s_2+n_1+n_2+u_1+u_2+k_1+k_2+e_1+e_2\le N 。对于每一个可行的方案,都会对答案产生 ( s 2 s 1 ) ( n 2 n 1 ) ( u 2 u 1 ) ( k 2 k 1 ) ( e 2 e 1 ) (s_2-s_1)(n_2-n_1)(u_2-u_1)(k_2-k_1)(e_2-e_1) 这么多贡献。要求求出总贡献。多组数据。

思路:正解好像是用插值法。但是似乎它的答案是一个线性递推式,所以可以暴力算出前 40 项左右,打表,然后用 BM 算法就过了。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include <bits/stdc++.h>
#include <cstdio>
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<LL,LL> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=40005;
const LL M=1e9+7;
struct linear_sequence
{
    LL res[maxn],base[maxn],_c[maxn],_md[maxn];
    VI Md;

    LL ksm(LL x,LL n)
    {
        LL ret=1;
        while(n)
        {
            if(n&1) ret=ret*x%M;
            x=x*x%M;
            n>>=1;
        }
        return ret;
    }
    void multi(LL *a,LL *b,int k)
    {
        REP(i,0,(k<<1)-1) _c[i]=0;
        REP(i,0,k-1) if(a[i]) REP(j,0,k-1)
            _c[i+j]=(_c[i+j]+a[i]*b[j])%M;
        REP_(i,k+k-1,k) if(_c[i]) REP(j,0,Md.size()-1)
            _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%M;
        REP(i,0,k-1) a[i]=_c[i];
    }
    int solve(LL n,VI a,VI b)
    {
        LL ans=0,pnt=0;
        int k=a.size();
        //assert(a.size()==b.size());
        REP(i,0,k-1) _md[k-1-i]=-a[i];
        _md[k]=1;
        Md.clear();
        REP(i,0,k-1) if(_md[i]) Md.pb(i);
        REP(i,0,k-1) res[i]=base[i]=0;
        res[0]=1;
        while((1ll<<pnt)<=n) pnt++;
        REP_(p,pnt,0)
        {
            multi(res,res,k);
            if((n>>p)&1)
            {
                REP_(i,k-1,0) res[i+1]=res[i];
                res[0]=0;
                REP(j,0,Md.size()-1) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%M;
            }
        }
        REP(i,0,k-1) ans=(ans+res[i]*b[i])%M;
        return (ans+M)%M;
    }
    VI BM(VI s)
    {
        VI C(1,1),B(1,1);
        int L=0,m=1,b=1;
        REP(n,0,s.size()-1)
        {
            LL d=0;
            REP(i,0,L) d=(d+(LL)C[i]*s[n-i])%M;
            if(!d) ++m;
            else if((L<<1)<=n)
            {
                VI T=C;
                LL c=M-d*ksm(b,M-2)%M;
                while(C.size()<B.size()+m) C.pb(0);
                REP(i,0,B.size()-1) C[i+m]=(C[i+m]+c*B[i])%M;
                L=n+1-L,B=T,b=d,m=1;
            }
            else
            {
                LL c=M-d*ksm(b,M-2)%M;
                while(C.size()<B.size()+m) C.pb(0);
                REP(i,0,B.size()-1) C[i+m]=(C[i+m]+c*B[i])%M;
                ++m;
            }
        }
        return C;
    }
    int get(VI a,LL n)
    {
        VI c=BM(a);
        c.erase(c.begin());
        REP(i,0,c.size()-1) c[i]=(M-c[i])%M;
        //for(int i:c) printf("%d ",i);
        //puts("");
        return solve(n,c,VI(a.begin(),a.begin()+c.size()));
    }
}ls;

int cal(int n)
{
    LL ret=0;
    REP(s1,0,n-4) REP(s2,s1+1,n-4) if(s1+s2<=n-4)
        REP(n1,0,n-4) REP(n2,n1+1,n-4) if(s1+s2+n1+n2<=n-3)
            REP(u1,0,n-4) REP(u2,u1+1,n-4) if(s1+s2+n1+n2+u1+u2<=n-2)
                REP(k1,0,n-4) REP(k2,k1+1,n-4) if(s1+s2+n1+n2+u1+u2+k1+k2<=n-1)
                    REP(e1,0,n-4) REP(e2,e1+1,n-4)
                    {
                        int tot=s1+s2+n1+n2+u1+u2+k1+k2+e1+e2;
                        if(tot>n) continue;
                        ret+=1ll*(s2-s1)*(n2-n1)*(u2-u1)*(k2-k1)*(e2-e1);
                    }
    return ret%M;
}

int f[]={
0,
0,
0,
0,
1,
11,
71,
341,
1346,
4598,
14038,
39138,
101193,
245443,
563447,
1232837,
2585672,
5222552,
10198232,
19316488,
35588718,
63933498,
112225058,
192839398,
324900532,
537499132,
874246012,
399637805,
207858088,
434820093,
274485959,
780358,
996765147,
793168065,
118878018,
966647141,
677996797,
52230779,
485540255,
147468710,
203524158,
94513877,
885277100,
};

int main()
{
    VI x;
    /*
    REP(i,1,50)
    {
        cout<<cal(i)<<','<<endl;
        //x.pb(cal(i));
    }
    */
    for(int i:f) x.pb(i);
    int T=read();
    while(T--)
    {
        int n=read();
        printf("%d\n",ls.get(x,n-1));
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/dragonylee/article/details/107402229