NOIP提高組模擬賽9

2022-09-19 17:03:10 字數 4108 閱讀 8099

考場跑了個dijstra就跑路,然後t了。。。。

其實dij用處不大,這題用bfs說不定還快點。但是直接大力bfs顯然同樣會t飛,考慮如何優化,問題的關鍵在於這張「圖」的「邊數」太多了,但是在bfs或者其他演算法dij中,每個點第一次被訪問就是該點的答案,也就是說,雖然我們多次掃到同乙個點,但真正有意義的只有第一次

注意二分的邊界,最大距離,乙個是k的兩端,還有就是反轉的區間靠近邊界。

code

#include #include #include#includeusing namespace std;

const int maxn=1000005;

bool flag[maxn],vis[maxn];

setjs,os;

set::iterator lt,rt,it;

queueq;

int d[maxn],n,k,m,s;

void getit(int x,int l,int r)else

}void pu(int x)

}int main()

for(int i=1;i<=n;++i)if(!flag[i])

memset(d,0x3f,sizeof(d));

d[s]=0;

q.push(s);if(s&1)js.erase(s);else os.erase(s);

while(!q.empty())

for(int i=1;i<=n;++i)

if(d[i]==d[n+3])printf("-1 ");

else printf("%d ",d[i]);

return 0;

}

感謝動動學長的題解

以下內容大多是抄的

首先對ab排序,這樣對結果是沒有影響的

最大的a與b不相等一定無解,否則一定有解

從大到小列舉每個高度s,對不同s分別處理

先看第乙個s

設\(f[i]\)為至少\(i\)行合法的方案數,這個i可以理解為欽定的,對與多於i行不合法的被多次重複計算,後面需要容斥(好像還是個二項式反演?)

\(f[i]=c_a^i\times (s^i\times ((s+1)^-s^))^b\)

首先在a行中選至少i行不合法,選擇方案數\(c_a^i\)

然後對每一列分開考慮

對於已選的i行,每個位置有\(0\)~\((s-1)\)共\(s\)種放法,總共\(s^i\)

對於未選的a-i行,每個位置有\((s+1)\)種放法\((s+1)^\)要保證這些行合法所以減去不合法的\(s^\)

那麼對於每一列,方案數為\((s+1)^-s^\),一共b列,所以是b次方

\(f[i]\)求出後我們需要容斥出合法的方案數,這裡直接放柿子,請自行理解主要是我不會證

\(res=\sum \limits_^a(-1)^i\times f[i]\)

貌似需要二項式反演,學了再回來補坑吧

然後我們來考慮一般情況,共三種

第二三種可以看成特殊的第一種,(最大的s也是),我們考慮如何處理那個l形狀的東西

先放柿子

\(f[i]=c_a^i\times (s^i\times ((s+1)^-s^))^b\times (s^i\times (s+1)^)^d\)

按照上面的方法我們再來解釋一下

首先我們需要選出i行不合法,但是c已經合法了,所以我們只能從a中選所以是\(c_a^i\)

考慮那\(b\)列,跟上面乙個道理,有\(i\)行不合法,\(a+c-i\)行合法

考慮\(c\)列同理,\(i\)行不合法,\(c-i\)行合法

容斥跟上面一樣

code

#include#include#includeusing namespace std;

const int maxn=100005;

const int mod=1e9+7;

long long a[maxn],b[maxn];

long long c[maxn],s[maxn<<1|1];

long long inv[maxn],jc[maxn],n;

long long qp(long long x,long long y)

return ans;

}void ycl()

long long getc(int a,int i)

long long work(int a,int b,int c,int d,int s)

return res;

}int main()

s[0]=unique(s+1,s+(n<<1)+1)-s-1;

int pa=n+1,pb=n+1,na=n,nb=n;

long long ans=1;

for(int i=s[0];i;--i)

printf("%lld\n",ans);

return 0;

}

對著學長的**和注釋理解了半天,終於理解了一點

總體思路是

對於第i個人,無論坐到哪個位置,距離最近的人的距離是一樣的,所以根據距離最近的人的距離來分層處理,偶數區間的選擇具有對稱性,所以求出一側更新另一側

繼承學長的光榮傳統(\(skyh\)大神傾情壓行**加注釋),具體內容看**注釋

code+注釋(注釋才是核心)

#include #include using namespace std;

const int maxn=1055;

int mod,n;

long long qp(long long x,long long y)

return ans;

}bool vis[maxn];//預處理時標記**坐了小g

int inv[maxn];//預處理逆元1/i

int cnt[maxn];//有多少距離最近的人距離為i的

int odd[maxn];//有多少距離最近的人距離為i的,區間長度為偶數的

int pos[maxn];//第i個小g坐的位置,(任意乙個合法位置)

int ans[maxn][maxn];//記錄答案

int dp[maxn][maxn];//dp[i][j]該層坐下了i個人,還剩j個偶區間沒有坐的概率

int g[maxn][maxn];//輔助陣列

int main()//找到當前最大區間(任一),lr記錄左右端點,這裡是開區間

int near=r-l>>1;//距離最近的人的距離

++cnt[near];if(r-l&1)++odd[near];//計數

pos[i]=l+near;//記錄位置

vis[l+near]=1;//標記位置

}int sum=n;//剩餘人數

for(int i=1;i<=n;++i)//按照距離最近的人的距離分層處理

if(cnt[i])else

if(cnt[i]-odd[i])

}for(int u=l;u<=end;++u)ans[l+j-1][pos[u]]=(ans[l+j-1][pos[u]]+oddw)%mod,ans[l+j-1][pos[u]+1]=(ans[l+j-1][pos[u]+1]+oddw)%mod;//對偶區間每個決策點更新答案

for(int u=end+1;u<=r;++u)ans[l+j-1][pos[u]]=(ans[l+j-1][pos[u]]+jddw)%mod;//奇區間

}for(int j=l;j<=end;++j){//偶區間

int l=pos[j]-i+1,r=pos[j]+i;//區間左右端點

for(int k=l;k<=r;++k)//區間內每個點

if(pos[j]!=k)//不能是決策點

for(int u=r+1;u<=n;++u){ //後面的小g

int s=(k

NOIP提高組模擬賽3

周圍大佬都說初中打過n遍,我乙個菜雞瑟瑟發抖。把斐波那契數列寫出來找了半天性質,用了半個多小時推出來 x兔子的父親,就是x減去是在斐波那契數列中最大的小於x的數 舉個栗子 13號兔子,應減去8,得到他的祖先5 10號兔子,應減去8,得到他的祖先2 預處理出斐波那契數列,然後讓ab中較大的到他的祖先,...

NOIP提高組模擬賽4

丹青千秋釀,一醉解愁腸 無悔少年枉,只願壯志狂 矩陣字首和加暴力 o n 2m 2 60pts有手就行 觀察資料範圍,猜測應該是求一種 o n 3 的演算法,想到之前做的題,應該是 n 2 枚舉行,n 處理乙個序列的答案,然後,就沒有然後了 對於乙個序列,求子段和為k的倍數,如何 o n 求解,考慮...

NOIP提高組模擬賽6

這題看著真熟啊,好像把之前的english,入陣曲雜糅了一下。首先,像入陣曲一樣計算出字首和 s 式子可以轉化為求 s r s l 1 equiv max mod k 像english一樣 用單調棧處理出以x為最大值的區間,分區間求解 每次列舉一側區間,已知max,只要知道另一側有多少與之餘數相同的...