「問題の解決策と8.21は、試験に反映します。」

<>はい

<第更新>


<テキスト>

ONE

説明

質問の人々のうちMagolorの良心があなたを見つけ、そしてあなたは、テーブル(MO)ツアー(NI)を再生したいです。

Magolor:「?殺すアリは何が良いの豚の国地主麻雀斜視図を殺す?????」

あなた:「がんトピック人!」

Magolor悲しい......「私は質問の人々のうち良心ああ印象を持っているという印象を与える必要があります!」

だから、Magolorは、よく知られているUNOを選びました。唯一の全体の周りに移動する、完全ではないUNOのルールに従ってプレイするUNOカード。取締役会は、3人のプレーヤー(あなた、Magolor、Magolor友人TTL)があります:

誰もがその後、副、手の中の最後の三の大勝利からなる5枚のカードを選択し、7枚のカードに触れます。

4色サイズのRGBYの色の独立した、ブランドと機能の一部、ここでは廃棄カードと同等の機能に分かれ写真0-9デジタルカードの無限の数によって、UNOカード、。

機能カードは、一般的に、常に最小と等しく、他のカードに関係なく、ライセンスのあらゆる種類、あらゆる手含むカード機能の構成に参加しません。例えば-1 4 4 4 4 <1 3 7 8 9、-1 3 3 4 4 = -1 -1 -1 2 =最小3。

他の例の手の大きさ:大きな大きなファーストクラスのブランドは、その後、内部格付に従って比較します。

値下げ

入力形式

データ列3の各後続セットの行データ番号Tの最初のセットは、各列に3から7枚のカードを行サンプル入力(-1破棄機能カード)の形態を参照してください。

まず、第2行動のMagolor、第三TTL行動カードを行っています。

隣接するデータ間の空白行のセット。

出力フォーマット

一つの出力勝利勝者;側の勝利により、2人の方が存在する場合、同様の形式の出力で敗者;並んで3人側であれば、出力を描画し、サンプルの出力形式を参照してください。

サンプル入力

7
Y1 R2 B3 G4 G5 Y1 G1
G1 G2 G3 G4 G5 Y1 G1
Y1 R2 R3 Y4 R5 Y1 G1

Y3 R1 R5 G4 Y1 -1 -1
R1 R3 R9 R0 G3 -1 -1
B3 B0 B4 B5 R1 -1 -1

R1 R3 R9 R0 G3 -1 -1
Y3 R1 R5 G4 Y1 -1 -1
B3 B2 B4 B5 R1 -1 -1

R1 R3 R9 R0 G3 -1 -1
B3 B2 B4 B5 R1 -1 -1
Y3 R1 R5 G4 Y1 -1 -1

-1 -1 -1 -1 -1 -1 -1
B0 R1 B2 R3 B4 R5 B6
G0 Y1 G2 Y3 G4 Y5 G6

B0 R1 B2 R3 B4 R5 B6
-1 -1 -1 -1 -1 -1 -1
G0 Y1 G2 Y3 G4 Y5 G6

B0 R1 B2 R3 B4 R5 B6
G0 Y1 G2 Y3 G4 Y5 G6
-1 -1 -1 -1 -1 -1 -1

サンプル出力

Draw!
I w1n!
Magolor w1n!
TTL w1n!
I l0se!
Magolor l0se!
TTL l0se!

解決

考场上看问题之后直接想到的就是大模拟,分类讨论,先求出最高等级,然后再同级比较,然后敲了一个半小时才过样例,最后只有\(40\)分,\(cena\)评测的还因为用了一个\(lmabda\)表达式\(CE\)了。

其实可以有很简单的写法,就是对每一副手牌评价一个权值,然后直接按照权值比较即可,剩下的就是输赢的分类讨论了,也不是很长。

权值设计的方法就是首先等级之间的权值差一定要足够大,然后就是按照比较优先级设置不同的权值,就和数位的进制一样,然后就可以直接比较了。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const char name[3][10] = {"I","Magolor","TTL"};
const int INF = 0x3f3f3f3f;
const long long Base[] = {-INF,0,(LL)1e5,(LL)2e5,(LL)3e5,(LL)4e5,(LL)5e5,(LL)6e5,(LL)7e5,(LL)8e5,(LL)9e5};
int _buc[20],num[20]; int *buc = _buc + 1;
long long val[20];
inline int read(void)
{
    int w = 0 , x = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
inline int find(int x)
{
    for (int i=9;i>=0;i--)
        if ( num[i] >= x )
            return num[i] -= x , i;
    return Base[0];
}
inline long long calc(void)
{
    memset( _buc , 0 , sizeof _buc );
    for (int i=1;i<=7;i++) buc[read()]++;
    if ( buc[-1] > 2 ) return Base[0];
    if ( buc[1] >= 2 && buc[3] && buc[4] && buc[5] ) return Base[10];
    if ( buc[1] && buc[3] && buc[5] && buc[7] && buc[9] ) return Base[9] + 1;
    if ( buc[0] && buc[2] && buc[4] && buc[6] && buc[8] ) return Base[9];
    for (int i=9;i>=4;i--)
    {
        int x = i;
        while ( x >= i - 4 && buc[x] ) x--;
        if ( x == i - 5 ) return Base[8] + i;
    }
    int a,b,c,d,e; long long ans = 0;
    memcpy( num , buc , 80 );
    a = find(5);
    ans = max( ans , a * 1LL + Base[7] );

    memcpy( num , buc , 80 );
    a = find(3) , b = find(2);
    ans = max( ans , a * 10LL + b * 1LL + Base[6] );

    memcpy( num , buc , 80 );
    a = find(4) , b = find(1);
    ans = max( ans , a * 10LL + b * 1LL + Base[5] );

    memcpy( num , buc , 80 );
    a = find(2) , b = find(2) , c = find(1);
    ans = max( ans , a * 100LL + b * 10LL + c * 1LL + Base[4] );

    memcpy( num , buc , 80 );
    a = find(3) , b = find(1) , c = find(1);
    ans = max( ans , a * 100LL + b * 10LL + c * 1LL + Base[3] );

    memcpy( num , buc , 80 );
    a = find(2) , b = find(1) , c = find(1) , e = find(1);
    ans = max( ans , a * 1000LL + b * 100LL + c * 10LL + e * 1LL + Base[2] );

    memcpy( num , buc , 80 );
    a = find(1) , b = find(1) , c = find(1) , d = find(1) , e = find(1);
    ans = max( ans , a * 10000LL + b * 1000LL + c * 100LL + d * 10LL + e * 1LL + Base[1] );
    return ans;
}
inline void solve(void)
{
    val[1] = calc() , val[2] = calc() , val[3] = calc();
    if ( val[1] == val[2] && val[2] == val[3] ) return puts("Draw!") , void();
    if ( val[1] == val[2] )
    {
        if ( val[3] < val[1] ) printf("%s l0se!\n",name[2]);
        else printf("%s w1n!\n",name[2]);
    }
    else if ( val[3] == val[2] )
    {
        if ( val[1] < val[2] ) printf("%s l0se!\n",name[0]);
        else printf("%s w1n!\n",name[0]);
    }
    else if ( val[1] == val[3] )
    {
        if ( val[2] < val[1] ) printf("%s l0se!\n",name[1]);
        else printf("%s w1n!\n",name[1]);
    }
    else if ( val[1] > val[2] && val[1] > val[3] ) printf("%s w1n!\n",name[0]);
    else if ( val[2] > val[1] && val[2] > val[3] ) printf("%s w1n!\n",name[1]);
    else if ( val[3] > val[1] && val[3] > val[2] ) printf("%s w1n!\n",name[2]);
}
int main(void)
{
    freopen("uno.in","r",stdin);
    freopen("uno.out","w",stdout);
    int T; scanf("%d",&T);
    while ( T --> 0 ) solve();
    return 0;
}

gcd

Description

众所周知,GCD的意思分别是是钢琴的索(5)、哆(1)和来(2)。因此求两个数字的最大公因数的函数 GCD(a,b) 又可以被称作索哆来函数。当然,广义索哆来函数 GCD(a,b,c,d,...)=GCD(a,GCD(b,c,d,...))。

现在Magolor有一棵n个点n-1条边的连通图状乐谱(???),乐谱中每个点有一个音高。

Magolor想求一条最长的路径,使得路径上的所有点(包括端点)的音高的广义索哆来函数值不是1。

Input Format

第一行输入正整数 。

第二行输入n个正整数,分别表示第i个点的音高ai。

接下来n-1行每行两个正整数,表示a和b之间有一条无向边。

Output Format

一个整数表示最长路径的长度(所包含的点数,包括端点)。

Sample Input

7
2 4 1 6 2 6 4
1 2
2 3
2 4
4 5
4 6
5 7

Sample Output

5

解析

看到这种\(gcd\)的题首先应该想到的是枚举因数或者倍数,然后这道题就有两种思路了。

第一个就是枚举因数,那么也就是说一条合法的路径必然有一个共同的因子,于是就可以树形\(dp\)\(f[x][d]\)代表以\(x\)为根的子树中共同包含\(x\)的第\(d\)个质因子的最长链,可以直接转移。

\[f[x][d]=\max_{y\in son(x),fac[y][d']=fac[x][d]}\{f[y][d']+1\}\]

然后顺带地更新答案即可。

第二种思路就是枚举倍数。我们可以先枚举一个节点,然后枚举这个节点权值的倍数,这样把这个节点倍数的其他节点都标记起来,然后设法有效地建立标记节点的森林,直接跑直径即可。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+20;
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
struct edge { int ver,next; } e[N*2];
int n,t,Head[N],a[N],ans;
vector < int > fac[N],f[N];
inline void insert(int x,int y) { e[++t] = (edge){y,Head[x]} , Head[x] = t; }
inline void input(void)
{
    n = read();
    for (int i=1;i<=n;i++)
        a[i] = read();
    for (int i=1;i<n;i++)
    {
        int x = read() , y = read();
        insert( x , y ) , insert( y , x );
    }
}
inline void init(void)
{
    for (int i=1;i<=n;i++)
    {
        int v = a[i];
        for (int j=2;j*j<=a[i];j++)
            if ( v % j == 0 )
            {
                fac[i].push_back( j );
                f[i].push_back( 0 );
                while ( v % j == 0 ) v /= j;
            }
        if ( v > 1 ) fac[i].push_back( v ) , f[i].push_back( 0 );
    }
}
inline void dp(int x,int fa)
{
    for (int i=Head[x];i;i=e[i].next)
    {
        int y = e[i].ver;
        if ( y == fa ) continue;
        dp( y , x );
        for (int j=0;j<fac[x].size();j++)
            for (int k=0;k<fac[y].size();k++)
                if ( fac[x][j] == fac[y][k] )
                    ans = max( ans , f[x][j] + f[y][k] ),
                    f[x][j] = max( f[x][j] , f[y][k] + 1 );
    }
}
int main(void)
{
    freopen("gcd.in","r",stdin);
    freopen("gcd.out","w",stdout);
    input();
    init();
    dp( 1 , 0 );
    printf("%d\n",ans+2);
    return 0;
}

lorem

Description

当然,人不能总是回忆过去,更要向前看。

Magolor准备为9102的选手们出一道题。当然是一道简单题,虽然2019年的选手可能不会这样认为。因为9102年与2019年相比变化很大,甚至连语言都相差甚远,Lorem Ipsum 在9102年已经成为世界唯一通用语言。显然,题目的题面是使用Lorem Ipsum 写的。

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmodtempor incididunt ut labore et dolore magna aliqua. Ut enim ad minimveniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex eacommodo consequat. Duis aute irure dolor in reprehenderit in volupta tevelit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.

这份题面不仅有文采,而且颇具迷惑性。作为一名要参加NOIP9102的选手,相信你可以一眼看出解决这道题的关键就是对于q个关于这个长度为n的序列A的询问(l,r,MOD) ,分别求出区间[l,r]内所有 dolor 的 ut 值的和对 MOD 取余的结果。

Input Format

第一行两个正整数n,q,分别表示序列A的长度和询问数目。

第二行有n个正整数,即序列A。

接下来q行,每行读入 l r MOD 表示一个询问,保证1<=l<=r<=n。

Output Format

输出文件包含 q 行,每行输出一个答案表示区间[l,r]内所有 dolor 的 ut 值的和对MOD取余的结果,即「所有2^(r-l+1)个子序列的「去除重复数字以后的和」的和」

Sample Input

5 5
1 2 2 3 4
1 2 233333
2 3 333333
1 5 5
3 5 15
2 4 8

Sample Output

6
6
1
6
0

解析

首先我们必须知道一个权值在区间内的贡献,假设区间为\([l,r]\),颜色\(x\)出现了\(k\)次,那么他的贡献就是\(x(2^{r-l+1}-2^{r-l+1-k})\)

然后这道题就好做了。考虑莫队,我们可以有效地维护出现次数的数组,这是莫队很容易实现的。但是由于模数不断在变化,所以不能直接维护答案。

我们考虑用一个均摊的莫队思路,也就是利用莫队维护颜色出现次数和一些其他的信息,然后在每一个询问区间移动结束后使用分块算法,在\(O(\sqrt n )\)的时间之内求出答案即可。

如何计算答案,我们考虑分块。首先,对于一个确定的颜色我们可以直接计算贡献,但是直接枚举颜色会超时。然后我们发现颜色不同的出现次数是不会超过\(\sqrt n\),于是我们就可以在维护一个\(sum\)数组,代表出现次数为某个值的颜色的权值和,然后也可以直接计算贡献。

しかし、そこに問題はありません以上の出現の数が異なる場合でも、です\(\ sqrtのN \)の種は、そのサイズがの値超えることがあり、\(\ sqrtのN \)を、便利列挙。数未満である場合したがって副ビットブロックに、\(\ SQRT N \) 寄与を直接列挙算出することができます。より大きい(\ SQRT N \)\により発生数よりも大きい場合、\(\ SQRT N \)色は超えていない\を(\ SQRT N \)種、直接寄与色計算を列挙する。

小さいがある\(トリック\)は、である(2 \)を\パワーブロックの前処理方法とについても\(BSGS \)の少なくとも一方ができるようになるように、同じアルゴリズムであるブロック\ログ(\ ) A。

\(コード:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+20 , SQRTN = 500;
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
struct query { int l,r,mod,id; } q[N];
int n,m,T,tot,Max,Mod,a[N],flag[N];
int cnt[N],num[SQRTN],s[SQRTN][N];
long long ans[N],_pow[2][SQRTN],sum[N];
inline void input(void)
{
    n = read() , m = read();
    for (int i=1;i<=n;i++)
        cnt[ a[i] = read() ] ++,
        Max = max( Max , a[i] );
    for (int i=1;i<=m;i++)
        q[i].l = read() , q[i].r = read() , q[i].mod = read() , q[i].id = i;
}
inline void init(void)
{
    T = sqrt(n);
    for (int i=1;i<=Max;i++)
        if ( cnt[i] > T ) num[++tot] = i , flag[i] = true;
    for (int i=1;i<=tot;i++)
        for (int j=1;j<=n;j++)
            s[i][j] = s[i][j-1] + ( a[j] == num[i] );
}
inline bool compare(query p1,query p2)
{
    if ( ( p1.l / T ) ^ ( p2.l / T ) )
        return p1.l < p2.l;
    else if ( ( p1.l / T ) & 1 )
        return p1.r < p2.r;
    else return p1.r > p2.r;
}
inline void insert(int p) { if ( flag[p] ) return; sum[cnt[p]] -= p; sum[++cnt[p]] += p; }
inline void remove(int p) { if ( flag[p] ) return; sum[cnt[p]] -= p; sum[--cnt[p]] += p; }
inline long long mul(long long a,long long b) { return a * b % Mod; }
inline void add(long long &a,long long b) { a += b; if ( a >= Mod ) a -= Mod; }
inline long long sub(long long a,long long b) { return a - b < 0 ? a - b + Mod : a - b; }
inline void calcpow(void)
{
    _pow[0][0] = _pow[1][0] = 1;
    for (int i=1;i<=T;i++)
        _pow[0][i] = mul( _pow[0][i-1] , 2 );
    for (int i=1;i<=T;i++)
        _pow[1][i] = mul( _pow[1][i-1] , _pow[0][T] );
}
inline long long quickpow(int x) { return mul( _pow[0][x%T] , _pow[1][x/T] ); }
inline void CaptainMo(void)
{
    sort( q+1 , q+m+1 , compare );
    memset( cnt , 0 , sizeof cnt );
    int l = 1 , r = 0;
    for (int i=1;i<=m;i++)
    {
        int ql = q[i].l , qr = q[i].r;
        long long res = 0;
        while ( ql < l ) insert( a[--l] );
        while ( qr > r ) insert( a[++r] );
        while ( ql > l ) remove( a[l++] );
        while ( qr < r ) remove( a[r--] );
        Mod = q[i].mod;
        calcpow();
        for (int j=1;j<=T;j++)
            add( res , mul( sum[j] % Mod , sub( quickpow(r-l+1) , quickpow(r-l+1-j) ) ) );
        for (int j=1;j<=tot;j++)
            add( res , mul( num[j] , sub( quickpow(r-l+1) , quickpow(r-l+1-s[j][r]+s[j][l-1]) ) ) );
        ans[q[i].id] = res;
    }
}
int main(void)
{
    freopen("lorem.in","r",stdin);
    freopen("lorem.out","w",stdout);
    input();
    init();
    CaptainMo();
    for (int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}

<あとがき>

おすすめ

転載: www.cnblogs.com/Parsnip/p/11386671.html