大一萌新,第一次打比賽,雖然是線下賽,但送氣球的環節還是很贊的!
這里主要是補一下自己的弱項和考試時沒有做出來的題目。
1002(鏈接之后再放,官方還沒公開題目...)
先說一下第二題,這個題一看就是個推式子的題目,容易發現,每一種方案的概率都是一樣的且都是\(m^n\),即每一次選擇技能都會有\(m\)種技能可選。接下來考慮最后對答案的貢獻,容易發現,統計貢獻時,哪種技能我們並不關心,我們關心的是它出現的次數,並且容易想到將每個技能分開考慮。考慮某個技能(例如技能1對答案的貢獻),首先他出現的次數我們要枚舉,比如出現了i次,那么在這種情況下,剩下(n-i)個位置,我們不確定,我們只知道了技能1不能再選了,那么技能1在這種情況下的方案數就是\((m-1)^{n-i}\),所以技能1對答案的總的貢獻為\(\sum_{i=1}^{n}C^{i}_{n}*(m-1)^{n-i}*i^2\),當然一共有m個技能,我們再將這個值乘以m就是我們最終的答案。
PS:代碼只是通過了樣例,還沒有跑過全部數據,官方還沒有公開題目...
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10,P=1e9+7;
int n,m;
ll jc[N],inv_jc[N];
inline ll power(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1) ans=ans*x%P;
x=x*x%P;
y>>=1;
}
return ans%P;
}
inline void prework()
{
int s=1e5+5;
jc[0]=inv_jc[0]=1;
for(int i=1;i<=s;++i) jc[i]=jc[i-1]*i%P;
inv_jc[s]=power(jc[s],P-2);
for(int i=s-1;i>=1;--i) inv_jc[i]=inv_jc[i+1]*(i+1)%P;
}
inline ll C(int n,int m)
{
return jc[n]*inv_jc[m]%P*inv_jc[n-m]%P;
}
int main()
{
// freopen("1.in","r",stdin);
prework();
int T;scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
ll ans=0;
for(int i=1;i<=n;++i)
{
ans=(ans+C(n,i)*power(m-1,n-i)%P*i*i%P)%P;
}
ans=ans*m%P;
ans=ans*power(power(m,n),P-2)%P;
printf("%lld\n",ans);
}
return 0;
}
1006
這種題,....,頭禿,這也就應驗了我們教練的一句話,考試前期千萬不要浪,到后期一定要任性起來...這種題其實看到題的時候就想過答案可能會很小,但沒敢寫,等下一次的區域賽一定要大膽起來!
1007
這個題感覺是有點虧的題了,考試的時候,隊友已經知道了做法,可他當時正在推數學式子,他給我講的時候我也沒喲聽進去...(我的鍋。)於是到最后這個題都沒有寫...
初看這個題,我是被他的對角線都不同給嚇倒的,人還是不能慫啊!
首先可以發現他要求的不同只是主對角線的元素不同,副對角線上的元素不同,並沒有說要將主對角線和副對角線上的元素全部不同,所以我們就可以分開考慮主對角線和副對角線。假如說我們預處理出以每個元素為中心的主對角線的最長長度l[i][j]和以該元素為中心的副對角線的最長長度r[i][j],那么以該元素為中心的符合條件的矩陣為\(\lceil\frac{min(l[i][j],r[i][j])}{2}\rceil\).接下來考慮怎么預處理以每個元素為中心的最長的對角線的長度,我們可以單獨的將每個對角線拉出來組成一個序列。這樣好操作。初始值,每個值都是1,然后將半徑r拓展,但有個比較顯然的結論就是若i-1的r不為1,則i的半徑至少為r-1,我們可以利用這個信息進行快速擴展。總的復雜度應該為O(n^2)的。代碼太丑了,勿看!!!
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=1e6+10;
int cnt[M],n,a[N][N],r1[N][N],r2[N][N];
//分別表示主對角線,副對角線的最長的長度。
inline bool check1(int x,int y,int d)
{
d--;
if(x-d>=1&&y-d>=1&&x+d<=n&&y+d<=n&&!cnt[a[x-d][y-d]]&&!cnt[a[x+d][y+d]]&&a[x-d][y-d]!=a[x+d][y+d]) return true;
return false;
}
inline bool check2(int x,int y,int d)
{
d--;
if(x-d>=1&&y+d<=n&&x+d<=n&&y-d>=1&&!cnt[a[x-d][y+d]]&&!cnt[a[x+d][y-d]]&&a[x-d][y+d]!=a[x+d][y-d]) return true;
return false;
}
inline solve1(int x,int y)
{
cnt[a[x][y]]++;
x++;y++;
while(x<=n&&y<=n)
{
if(r1[x-1][y-1]==1)
{
cnt[a[x-1][y-1]]--;
cnt[a[x][y]]++;
int d=2;
while(check1(x,y,d))
{
cnt[a[x-d+1][y-d+1]]++;
cnt[a[x+d-1][y+d-1]]++;
d++;
}
r1[x][y]=d-1;
}
else
{
int d=r1[x-1][y-1];
cnt[a[x-r1[x-1][y-1]][y-r1[x-1][y-1]]]--;
cnt[a[x-r1[x-1][y-1]+1][y-r1[x-1][y-1]+1]]--;
while(check1(x,y,d))
{
cnt[a[x-d+1][y-d+1]]++;
cnt[a[x+d-1][y+d-1]]++;
d++;
}
r1[x][y]=d-1;
}
x++;y++;
}
x--;y--;
cnt[a[x][y]]--;
}
inline solve2(int x,int y)
{
cnt[a[x][y]]++;
x++;y--;
while(x<=n&&y>=1)
{
if(r2[x-1][y+1]==1)
{
cnt[a[x-1][y+1]]--;
cnt[a[x][y]]++;
int d=2;
while(check2(x,y,d))
{
cnt[a[x-d+1][y+d-1]]++;
cnt[a[x+d-1][y-d+1]]++;
d++;
}
r2[x][y]=d-1;
}
else
{
int d=r2[x-1][y+1];
cnt[a[x-r2[x-1][y+1]][y+r2[x-1][y+1]]]--;
cnt[a[x-r2[x-1][y+1]+1][y+r2[x-1][y+1]-1]]--;
while(check2(x,y,d))
{
cnt[a[x-d+1][y+d-1]]++;
cnt[a[x+d-1][y-d+1]]++;
d++;
}
r2[x][y]=d-1;
}
x++;y--;
}
x--;y++;
cnt[a[x][y]]--;
}
int main()
{
// freopen("1.in","r",stdin);
int T;scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
scanf("%d",&a[i][j]);
r1[i][j]=r2[i][j]=1;
}
for(int i=1;i<=n;++i)//處理主對角線
{
solve1(i,1);//分別以(i,1)開始的對角線。
solve1(1,i);//分別以(1,i)開始的對角線。
}
for(int i=1;i<=n;++i)//處理副對角線
{
solve2(1,i);//以(1,i)
solve2(i,n);//以(i,m)
}
int ans=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
r1[i][j]=2*r1[i][j]-1;
r2[i][j]=2*r2[i][j]-1;
ans+=ceil(min(r1[i][j],r2[i][j])/2.0);
}
}
printf("%d\n",ans);
}
return 0;
}