test20190825 AmberFrame

100 + 0 + = 199 99、第二の問題は、分割されないことができませんでした。

カウント

与えられた\(\ N-) 法的追求\((X_1、X_2、X_3 、\ドット、X_)\ {2メートル}) の配列を。集合\(X \)の場合にのみ、有効である
\ [\ iが[IN \ FORALL 1,2m]、X_I \で\ mathrm {Z} _ +、X_I \ミッドN \\ \のprod_ {I = 1} ^ {2メートル} X_I =
N ^ Mの\] 正当\((X_1、X_2、X_3 、\ドット、X_ {})\の2M) 多く、あなたに番号をしてください出力方式が存在してもよい(\ \ BMOD 998244353 \)

\(N \の当量^ 9 10、m個の\当量100 \)

問題の解決策

右のエントリポイントを見つけるのに長い時間をお読みください。

私はすべてを取るカウントを開始し、\(\ log_n \) 乗算ほかになろうと。これは、エラーの精度は、実際の効果はDFSとの違いではないことを見出しました。

その後、私は突然それぞれに考え\(X_I \)となる(\ \ N-FRAC {} {X_I})\、正確に逆の製品。だから、答えはで割ったすべてのケースである(2 \)\少し考えたのは、全く正しい、と等しいがあるかもしれないでしょう(\ PRODのX_I = N ^ \ m個\) 状況。そこで問題は、等号に変換します。

私も紆余曲折の多くを費やして、この問題を解決します。最初に考えたのは、最後の素因数が別々のカウント乗算原理と組み合わせることができました。

それから私は、組み合わせの数である各品質係数を考えました。フォームの品質係数とし\(P-^ \アルファ\)を、そして答えはそれではありません\(\メートルの\アルファ)は、に分割され(2メートル\)\ナンバースキーム自然数右?私は巧みに答えを書いて\(\ Binom {Mの\ +アルファ2M-2M。1. 1} {} \) サンプルが小さすぎます。

その後、マニュアルを開始し、私は答えが間違っていた映画の暴力を書き始めました。例えば、データのセット:161。長い時間のためのトーンは各分割インデックスのために発見された\(Y \)を満たす必要があります\(0 \のLeq Y \のLeq \アルファ\を)少し自閉症。

最終的にDP、その後、いくつかの小さなミスを見つけるには、最終的には二つのプログラムを引き受けました。

#include<bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
template<class T> T read(){
    T x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x;
}
template<class T> T read(T&x){
    return x=read<T>();
}
#define co const
#define il inline
typedef long long LL;

co int mod=998244353,i2=499122177;
il int add(int a,int b){
    return (a+=b)>=mod?a-mod:a;
}
il int mul(int a,int b){
    return (LL)a*b%mod;
}
il int fpow(int a,int b){
    int ans=1;
    for(;b;b>>=1,a=mul(a,a))
        if(b&1) ans=mul(ans,a);
    return ans;
}

int f[201][3001];
int dp(int n,int m,int lim){
//  cerr<<"n="<<n<<" m="<<m<<endl;
    for(int i=0;i<=n;++i) fill(f[i],f[i]+m+1,0);
    f[0][0]=1;
    for(int i=0;i<n;++i)
        for(int j=0;j<=m;++j)if(f[i][j])
            for(int k=0;k<=lim&&k<=m-j;++k) f[i+1][j+k]=add(f[i+1][j+k],f[i][j]);
    return f[n][m];
}
int main(){
    freopen("count.in","r",stdin),freopen("count.out","w",stdout);
    int n=read<int>(),m=read<int>();
    
    int ans=0;
    for(int i=1;i*i<=n;++i)if(n%i==0){
        ++ans;
        if(n/i!=i) ++ans;
    }
    ans=fpow(ans,2*m);
    
    int nn=n,sum=1;
    for(int i=2;i*i<=n;++i)if(nn%i==0){
        int c=0;
        while(nn%i==0) nn/=i,++c;
        sum=mul(sum,dp(2*m,m*c,c));
    }
    if(nn>1) sum=mul(sum,dp(2*m,m,1));
//  cerr<<"ans="<<ans<<" sum="<<sum<<endl;
    printf("%d\n",mul(add(ans,sum),i2));
    return 0;
}

削除

シーケンスを考えると、あなたは継続的な操作で、このシーケンスを排除する必要があります。たびに、それを削除するには上下にシーケンスを選択する残りのシーケンス新しいシーケンスとして、削除を続行することができます。操作が終了するまで、新しいシーケンスは空です。

複数言語の形で次のように具体的には、一つの操作が表すことができる:(Xのシーケンスのために。1、X 2、...、X N - )、一つの操作は≤Aの1を選択することができる1。 <A 2 <... <A Kの ≤のN-、X A 1、X 、A 2、...、X A Kは省略する。ここで、KとA 私はあなたが決めるが、X満たす必要ができているAを。1 <X A 2 <... <X 、K、またはX A 。1 > X A 2 > ...> X K

私たちは、あなたが任意の出力シーケンスモード、データが保証されている解決策が存在する削除、あなたは500で、空のシーケンスを削除することを願っています。
便宜上、ことを確保するため、(X 1、X 2、...、X N-は)1..nの中に配置されています。

nは64000を≤。

問題の解決策

私は0をバースト、なぜいくつかのSPJを観察した後、最終的に知っています。彼は、xの値ではなく位置である出力素子、ことを尋ねました。

削除

欲は大丈夫見つけることができます。何ディルワース定理?

ディルワース定理

プロモーター配列はディルワース定理は、分割の最小数の配列を最適化するために使用することができる減少しません。

関連の定義

部分的な順序関係は反射的、反対称二項関係、推移を満たしています。それは≤表現することができます。

  • 再帰性:X≤xが成り立ちます。
  • 反対称:↔A = B≤≤bとB
  • 传递性:≤bは≤のC且B→≤Cの

セットの半順序関係と呼ばれるPoset明らかに設定された数は、部分的な順序ですが、部分的にしかオーダーが数に設定することができます「以下です」。

  • 匹敵する:AとBは場合に限り、≤bまたはB≤、同等です。

集合Uが設定posetです。

  • チェーン:Uの部分集合が同等(同一ではない)任意の2つの要素を満たします。
  • 逆方向鎖:Uの部分集合は、同等(同一ではない)ではない任意の2つの要素を満たします。

例えば、集合Sに等しい有限数の最長の鎖の長さ| S | 1つのトランスの、最長鎖長。

Uと呼ばれる多くのサブセットに分割部門仮鎖分裂と呼ばれる全体のチェーンの分割に設定ハンドル、全体の抗連鎖抗チェーンに分割されていると呼ばれます。

定理コンテンツ

二元性の二つの相互定理があります。

  1. Uは、最大の逆鎖長に等しいチェーンを使用して分割の最小数を設定します。
  2. Uは、抗鎖、その最大値に等しい鎖長で使用される分割の最小数を設定します。

一つが呼び出されディルワース定理

戻る質問へ:実数の全配列を考えると、順番に選択して削除され、それぞれがそれをドロップしません。必要な完全な配列を削除しようとしているのシーケンスの数を選択します。例えば、12435シーケンス、少なくとも二倍、初めて1235。

異なる配列のコレクションが、これは、少なくとも分割に関連してもよいです。とにかく、意図定理に関連するコンテンツディルワースは、この問題を解決します。

まず、シーケンスは、コレクションに変換する必要があります。要素の順序付けられたシーケンス点が異なります。いくつかの順序付けられた対の使用を検討した(p、v)を元のシーケンスにおける数を表します。pは位置を表し、Vは値を表します。

コレクションから任意の2つの要素を削除し、後者よりも前者はどのくらいを決定することができますか?関係≤考えてみましょう:P- 1 P-≤ 1とをV 1 ≤V 2これは、元の配列の位置に従って順序付け二つの第一の要素に対応し、そして次に数値サイズを比較します。この関係は半順序です。したがって、元の配列に相当する同等の2つの要素は、それらが落下されていません。

(1)によれば、最長シーケンスドロッププロ配列の長さに等しい原稿の質問の数。

次に、分割シーケンスの最小数を減少させる、最も長い配列の長さに等しいが低減されません。


劉は、マスターリスト+ツリーラインとTLEを書きました。これは、タイトルカード定数と思われます。

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <memory.h>
#include <vector>

using namespace std;
typedef long long LL;

const int maxn = 64005;
#define pb push_back

int a[maxn],a0[maxn],n,tot,f[maxn],g[maxn];
vector<int> vec[maxn];
int mx1[maxn],mx2[maxn],bac[maxn],del[maxn];

void Print()
{
    printf("%d\n",tot);
    for (int i=1;i<=tot;i++)
    {
        int len=vec[i].size();
        printf("%d ",len);
        for (int j=len-1;j>=0;j--)
            printf("%d%c",vec[i][j]," \n"[j==0]);
    }
}
void insert1(int x,int v) {
    for (int i=x;i<=n;i+=i&-i)
        mx1[i]=max(mx1[i],v);
}
void insert2(int x,int v) {
    for (int i=x;i;i-=i&-i)
        mx2[i]=max(mx2[i],v);
}
int query1(int x) {
    int res=0;
    for (int i=x;i;i-=i&-i)
        res=max(res,mx1[i]);
    return res;
}
int query2(int x) {
    int res=0;
    for (int i=x;i<=n;i+=i&-i)
        res=max(res,mx2[i]);
    return res;
}

void DP()
{
    ++tot;
    memset(mx1,0,n+1<<2);
    memset(mx2,0,n+1<<2);
    int ans1=0,ans2=0;;
    for (int i=1;i<=n;i++)
    {
        f[i]=query1(a[i])+1;
        g[i]=query2(a[i])+1;
        insert1(a[i],f[i]);
        insert2(a[i],g[i]);
        ans1=max(ans1,f[i]);
        ans2=max(ans2,g[i]);
    }
    
    memset(del,0,n+1<<2);
    if (ans1>ans2) {
        for (int t=ans1,i=n;t;i--)
            if (f[i]==t) del[a[i]]=1,t--,vec[tot].pb(a0[i]);
    }
    else {
        for (int t=ans2,i=n;t;i--)
            if (g[i]==t) del[a[i]]=1,t--,vec[tot].pb(a0[i]);
    }
    for (int i=1;i<=n;i++)
        bac[i]=bac[i-1]+1-del[i];
    int pos=0;
    for (int i=1;i<=n;i++)
        if (!del[a[i]]) a0[++pos]=a0[i],a[pos]=bac[a[i]];
    n=pos;
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("delete.in","r",stdin);
        freopen("delete.out","w",stdout);
    #endif
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]),a0[i]=a[i];
    while (n) DP();
    Print();
    return 0;
}

オーダー\(X = \ FRAC {\のSQRT {+1しました。5} {2}} \) シーク\(\ X ^ N-lfloor \ rfloor \ MOD P \)

\(N \の当量10 ^ {18}、p個の\の当量998 244 353 \)

問題の解決策

まったく同じJLOI2015意味のある文字列最初の列の数を見つけるために対応する、繰り返し試みが見つける
\ [\左(\ FRAC { 1+ \ SQRT {5}} {2} \右)^ N + \左(\ FRAC {1- \ SQRT {5}} { 2} \右)^ N \
] この式は、列の数に対応する\(1,3,4,7,11,18 \ DOTS \) その後、列数を取得するために迅速なパワーマトリックスを作成します。

小数点記号の後にカットに基づいて回答するかどうか注意裁判官\(1 \)

#include<bits/stdc++.h>
using namespace std;
template<class T> T read(){
    T x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x;
}
template<class T> T read(T&x){
    return x=read<T>();
}
#define co const
#define il inline
#define int long long

int mod;
struct mat{
    int v[2][2];
    il int*operator[](int i) {return v[i];}
    il co int*operator[](int i)co {return v[i];}
};
mat operator*(co mat&a,co mat&b){
    mat c;memset(c.v,0,sizeof c.v);
    for(int i=0;i<2;++i)
        for(int j=0;j<2;++j)
            for(int k=0;k<2;++k)
                c[i][j]=(c[i][j]+a[i][k]*b[k][j])%mod;
    return c;
}
mat pow(mat a,int b){
    mat ans;memset(ans.v,0,sizeof ans.v);
    for(int i=0;i<2;++i) ans[i][i]=1;
    for(;b;b>>=1,a=a*a)
        if(b&1) ans=ans*a;
    return ans;
}

signed main(){
    freopen("floor.in","r",stdin),freopen("floor.out","w",stdout);
    int n=read<int>();read(mod);
    if(n==0) {puts("1");return 0;} // edit 1
    mat a=pow((mat){0,1,1,1},n-1);
    int ans=(a[0][0]+3*a[0][1])%mod;
    if(~n&1) ans=(ans+mod-1)%mod;
    printf("%lld\n",ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/autoint/p/test20190825.html