考場跑了個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,只要知道另一側有多少與之餘數相同的...