1. 程式人生 > >10.25模擬賽

10.25模擬賽

space 其他 char s 很難 pytho getc script rip 遊戲

NP(np)

Description

LYK 喜歡研究一些比較困難的問題, 比如 np 問題。

這次它又遇到一個棘手的 np 問題。 問題是這個樣子的: 有兩個數 n 和 p, 求 n 的階乘 對 p 取模後的結果。

LYK 覺得所有 np 問題都是沒有多項式復雜度的算法的,所以它打算求助即將要參加 noip 的你, 幫幫 LYK 吧!

Input

? 輸入一行兩個整數 n,p。

Output

輸出一行一個整數表示答案。

數據範圍

對於 20%的數據: n,p<=5。

對於 40%的數據: n,p<=1000。

對於 60%的數據: n,p<=10000000。

對於 80%的數據: n<=10^18, p<=10000000。

對於另外 20%的數據: n<=10^18, p=1000000007。

其中大致有 50%的數據滿足 n>=p

很顯然的是,當\(n \geq p\)的時候,直接輸出\(0\)

此時,求解\(n\)的階乘的時候會乘上一個\(p\)

則代表\(n=k \times p\)

然後呢,其他部分的分怎麽得?

分段打表!

我們打出\(10^7\)\(10^9\)部分的階乘\(%1000000007\)的值.

然後遇到\(p=1000000007\)的情況的時候,我們可以直接跳到這一倍數位置.後面部分暴力擴展即可.

復雜度\(O(能夠)\)

還玩了半天\(python\) ~w~

代碼

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<cctype>
#define int long long 
#define R register
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,p,res=1;
const int fac[]=
{
    1,682498929,491101308,76479948,723816384,67347853,27368307,625544428,199888908,888050723,927880474,281863274,661224977,623534362,
    970055531,261384175,195888993,66404266,547665832,109838563,933245637,724691727,368925948,268838846,136026497,112390913,135498044,217544623,
    419363534,500780548,668123525,128487469,30977140,522049725,309058615,386027524,189239124,148528617,940567523,917084264,429277690,996164327,
    358655417,568392357,780072518,462639908,275105629,909210595,99199382,703397904,733333339,97830135,608823837,256141983,141827977,696628828,
    637939935,811575797,848924691,131772368,724464507,272814771,326159309,456152084,903466878,92255682,769795511,373745190,606241871,825871994,
    957939114,435887178,852304035,663307737,375297772,217598709,624148346,671734977,624500515,748510389,203191898,423951674,629786193,672850561,
    814362881,823845496,116667533,256473217,627655552,245795606,586445753,172114298,193781724,778983779,83868974,315103615,965785236,492741665,
    377329025,847549272,698611116
};
signed main()
{
    freopen("np.in","r",stdin);
    freopen("np.out","w",stdout);
    in(n),in(p);
    if(n>=p){puts("0");return 0;}
    if(p==1000000007)
    {
        int now=n/10000000;
        int res=fac[now];
        for(R int i=now*10000000+1;i<=n;res*=i,res%=p,i++);
        printf("%lld",(res<0)?(res+p)%p:res%p);
        return 0;
    }
    for(R int i=1;i<=n;res*=i,res%=p,i++);
    printf("%lld",(res<0)?(res+p)%p:res%p);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

看程序寫結果(program)

Description

LYK 最近在準備 NOIP2017 的初賽, 它最不擅長的就是看程序寫結果了, 因此它拼命地 在練習。

這次它拿到這樣的一個程序:

Pascal:
readln(n);
for i:=1 to n do read(a[i]);
for i:=1 to n do for j:=1 to n do for k:=1 to n do for l:=1 to n do
if (a[i]=a[j]) and (a[i]<a[k]) and (a[k]=a[l]) then ans:=(ans+1) mod 1000000007;
writeln(ans);
C++:
pcanf(“%d”,&n);
for (i=1; i<=n; i++) scanf(“%d”,&a[i]);
for (i=1; i<=n; i++) for (j=1; j<=n; j++) for (k=1; k<=n; k++) for (l=1; l<=n; l++)
if (a[i]==a[j] && a[i]<a[k] && a[k]==a[l]) ans=(ans+1)%1000000007;
printf(“%d\n”,ans)

LYK 知道了所有輸入數據, 它想知道這個程序運行下來會輸出多少。

Input

第一行一個數 n, 第二行 n 個數, 表示 ai。

Output

一個數表示答案。

數據範圍

數據範圍

對於 20%的數據 n<=50。

對於 40%的數據 n<=200。

對於 60%的數據 n<=2000。

對於 100%的數據 n<=100000, 1<=ai<=1000000000

其中均勻分布著 50%的數據不同的 ai 個數<=10, 對於另外 50%的數據不同的 ai 個 數>=n/10。

這題得分最簡單了把上面代碼粘下來都有40pts

首先你需要離散化.這個看不出來就不怪我了啊

很容易發現,

這題要找滿足這個條件的東西數量.
\[ a[i]==a[j] &&a[i]<a[k] &&a[k]==a[l] \]
但是你看它枚舉的順序,先別在乎\(n^4\)

如果\(i==j\)依舊成立.即一個數可以和自己組合.

同時又可以和已經組合過的數組合.

然後如果有\(n\)個數的話,兩兩組合有多少個方案?建議手玩

\(n \times (n-1) + n\)

\(+n\)即自己和自己組合的方案.

我竟然沒看出來是\(n^2\),然後直接寫了這個式子.

代碼還取了很多模,可醜了

顯然現在的答案就是
\[ \sum_{i=1}^{cnt}num_i^2\times \sum_{j=i+1}^{cnt}num_j^2 \]
代碼中並不是這樣寫的.忘了化簡式子但是是一樣的.

然後我們可以維護一個後綴和,達到\(O(n)\)求解.

總復雜度\(O(nlogn)\)

代碼

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<cctype>
#define N 100008
#define ll long long
#define mod 1000000007
#define R register
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,a[N],b[N];
int tong[N],mx,cnt=1;
ll ans,sum[N];
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    in(n);
    for(R int i=1;i<=n;i++)
        in(a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    for(R int i=2;i<=n;i++)
        if(b[i]!=b[cnt])b[++cnt]=b[i];
    for(R int i=1;i<=n;i++)
    {
        a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
        (tong[a[i]]+=1)%=mod;
    }
    for(R int i=cnt;i>=1;i--)
        sum[i]=(sum[i+1]%mod+(((tong[i]%mod)*((tong[i]-1)%mod)%mod)*1LL+(tong[i]%mod)*1LL))%mod;
    for(R int i=1;i<cnt;i++)
    {
        R ll tmp=(((tong[i]%mod)*((tong[i]-1)%mod)*1LL)+tong[i])*1LL;
        (ans+=tmp*sum[i+1])%=mod;
    }
    printf("%lld",(ans<0) ? (ans+mod)%mod:ans%mod);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

選數字(select)

Description

LYK 找到了一個 n*m 的矩陣, 這個矩陣上都填有一些數字, 對於第 i 行第 j 列的位置上 的數為 ai,j。

由於它 AK 了 noip2016 的初賽, 最近顯得非常無聊, 便想到了一個方法自娛自樂一番。 它想到的遊戲是這樣的: 每次選擇一行或者一列, 它得到的快樂值將會是這一行或者一列的 數字之和。 之後它將該行或者該列上的數字都減去 p(之後可能變成負數)。 如此, 重復 k 次, 它得到的快樂值之和將會是它 NOIP2016 復賽比賽時的 RP 值。

LYK 當然想讓它的 RP 值盡可能高, 於是它來求助於你

Input

第一行 4 個數 n,m,k,p。

接下來 n 行 m 列, 表示 ai,j

Output

輸出一行表示最大 RP 值

正解貪心.

開兩個堆分別維護

  1. \(ansx[i]\)代表在\(n\)行中選擇最大值\(i\)次的答案.
  2. \(ansy[i]\)代表在\(m\)列中選擇最大值\(i\)次的答案.

然後枚舉選\(i\)次行,那麽我們就知道選\(k-i\)次列.

但是我們重復減去了一些東西,再加上就好了,應該不是很難理解.就不多BB了

註意極小值一定要夠小!!!

代碼

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<cctype>
#define int long long 
#define R register
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,m,k,p;
int mx=-2147483644666666LL;
int xx[1008],yy[1008];
priority_queue<int>q;
priority_queue<int>Q;
int ansx[1000008],ansy[1000008],ans;
inline int get()
{
    R int res=-2147483644666666LL,pos,flg;
    for(R int i=1;i<=n;i++)
        if(xx[i]>res)res=xx[i]*1LL,flg=1,pos=i;
    for(R int j=1;j<=m;j++)
        if(yy[j]>res)res=yy[j]*1LL,flg=2,pos=j;
    if(flg==1)
    {
        for(R int i=1;i<=m;i++)
            yy[i]-=p;
        xx[pos]-=m*p;
    }
    if(flg==2)
    { 
        for(R int i=1;i<=n;i++)
            xx[i]-=p;
        yy[pos]-=n*p;
    }
    return res;
}
signed main()
{
    freopen("select.in","r",stdin);
    freopen("select.out","w",stdout);
    
    in(n),in(m),in(k),in(p);
    
    if(n<=5 and m<=5 and k<=5)
    {
        for(R int i=1;i<=n;i++)
            for(R int j=1,x;j<=m;j++)
                in(x),xx[i]+=x,yy[j]+=x;
        for(R int i=1;i<=k;i++)ans+=get();
        printf("%lld",ans);
        return 0;
    }//20pts;
    
    
    if(p==0 or k==1)
    {
        for(R int i=1;i<=n;i++)
            for(R int j=1,x;j<=m;j++)
                in(x),xx[i]+=x,yy[j]+=x;
        for(R int i=1;i<=n;i++)mx=max(1LL*xx[i],mx);
        for(R int i=1;i<=m;i++)mx=max(1LL*yy[i],mx);        
        printf("%lld",mx*(k*1LL));
        return 0;
    }//20pts;
    
    
    for(R int i=1;i<=n;i++)
        for(R int j=1,x;j<=m;j++)
            in(x),xx[i]+=x,yy[j]+=x;
    for(R int i=1;i<=n;i++)q.push(1LL*xx[i]);
    for(R int i=1;i<=m;i++)Q.push(1LL*yy[i]);
    for(R int i=1;i<=k;i++)
    {
        R int x=q.top();
        q.pop();
        ansx[i]=ansx[i-1]+x;
        q.push(x-p*m);
        
        R int y=Q.top();
        Q.pop();
        ansy[i]=ansy[i-1]+y;
        Q.push(y-p*n);
    }
    ans=-2147483644666666LL;
    for(int i=0;i<=k;i++)
        ans=max(ans,ansx[i]+ansy[k-i]-i*(k-i)*p);
    printf("%lld",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

10.25模擬賽