noip前准備日記
csp就把它埋了吧。
Day -26
剛考完csp,沒有考試。。
刷了幾個好題。。
P3076 [USACO13FEB] TaxiG
這個題目硬想是不好想的,但是我們可以分步來做。
首先我們知道每個 \(s_i\) 到 \(t_i\) 的距離一定是一定的。
我們沒有辦法避免,所以就要先加上這個東西。
之后我們就要送完每個奶牛之后去接下一個。
這個東西是我們需要仔細想的。
每一個奶牛的行程還是相當一條線段,我們現在的主要任務就是將這些線段用最小的代價收尾相接起來。
那么我們就可以將每一個起點的坐標進行排序,然后將每一個終點的坐標進行排序,之后按位相減的一定就是代價最小的答案。
可是這樣的話就少掉了終點和起點的路程。
因為我們從起點出發一定會先去找到一個起點去接奶牛,終點之前也一定是一個終點才對。
所以我們就可以把終點塞到起點的排序的數組中,把起點塞到終點的,然后再去排序。
按位相減就能得到最優的答案了。
那么這個結論如何證明呢??
我們如果都進行排序之后,如果任意交換一對數值,那么得到的代價一定會變大。
所以排序后的就一定是最小的。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next.y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
#define int long long
namespace xin
{
int s[maxn],t[maxn];
int n,m,ans;
inline short main()
{
io >> n >> m;
try(i,1,n) io >> s[i] >> t[i],ans += abs(s[i] - t[i]);
s[n+1] = m; t[n+1] = 0;
std::sort(s+1,s+n+2); std::sort(t+1,t+n+2);
try(i,1,n+1) ans += abs(s[i] - t[i]);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
[NOIP2018 提高組] 賽道修建
首先這個題目問的最大的最小值就能一眼看出來這就是一個二分答案。
那么我們該如何進行check就是問題所在了。
我們首先一定是想要讓賽道的數量是盡可能多的。
所以我們如果首先選擇離根節點比較近的節點,那么就會損失掉更多的賽道。
所以我們首先遞歸到最下面開始貪心。
現在就有一個問題,就是我們手上有一個序列,然后我們需要找到最小的值使得兩個不同的數 \(x\),\(y\)使得 \(x+y\ge val\),之前考到過一個 meet in middle
的題目自己當時並不知道該如何在小於 \(\mathcal O(n^2)\) 的復雜度下求出這個東西。
然后就學到了二分可以做到,所以我們在一個序列上面進行二分。
但是我們需要判斷重復,如果重復,那么將指針加一一定是最優的選擇。
之后我們對於沒有被選到的邊進行傳遞,顯然只能傳遞一個,那么最大的一定就是最優的情況。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
#define int long long
namespace xin
{
class xin_edge{public:int next,ver,w;}edge[maxn];
int head[maxn],rp;
inline void add(int x,int y,int z) {edge[++rp].ver = y; edge[rp].next = head[x]; edge[rp].w = z; head[x] = rp;};
int n,m,he = 0,ret;
int pre[maxn],temp[maxn],zhi = 0,vis[maxn];
void dfs(int x,int fa,int val)
{
// jb(x);
go(i,x) if(y != fa) dfs(y,x,val);
zhi = 0;
go(i,x) if(y != fa) temp[++zhi] = pre[y] + edge[i].w;
std::sort(temp+1,temp+zhi+1);
// jb(x);
// try(i,1,zhi) cout<<temp[i]<<' ';
// cout<<endl;
while(temp[zhi] >= val) ret --,zhi --;
// jb(ret);
try(i,1,zhi) if(vis[i] != x)
{
int pos = std::lower_bound(temp+1,temp+zhi+1,val - temp[i]) - temp;
// sb(i);sb(val - temp[i]);jb(pos);
while(pos <= zhi and (vis[pos] == x or pos == i)) pos ++;
// jb(pos);
if(pos <= zhi) vis[pos] = vis[i] = x,ret --;
}
throw(i,zhi,1) if(vis[i] != x) {pre[x] = temp[i]; break;}
}
inline int check(int x)
{
memset(vis,0,sizeof(int) * (n + 1));
memset(pre,0,sizeof(int) * (n + 1));
ret = m;
dfs(1,0,x);
return ret <= 0;
}
inline short main()
{
io >> n >> m;
try(i,1,n-1)
{
register int x,y,z; io >> x >> y >> z;
add(x,y,z); add(y,x,z); he += z;
}
// go(i,1) jb(y);
int l = 0,r = he,ans = 0;
// jb(r);
// cout<<check(7987)<<endl;
// return 0;
while(l <= r)
{
register int mid = l + r >> 1;
if(!check(mid)) r = mid - 1;
else l = mid + 1,ans = mid;
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
[CSP-S 2021] 廊橋分配
紀念一下爆炸的csp吧。
思路是對的,但是確實實現假掉了,最后20min什么其實也救不回來,頂多就是一個文件名什么的。
首先我們一定會有一個 \(40pts\) 的 \(\mathcal O(n^2log)\) 的做法。
然后我刪了
就是對於每一種分配方式然后 \(\mathcal O(nlog)\) 進行 \(check\)
但是呢,這個不夠優秀。
所以我們考慮如何優化 \(check\)。
我們其實可以挨個考慮貢獻,我們首先進行一遍預處理。
也其實就是模擬這個過程一遍,然后我們就可以發現在當時有 \(x\) 個廊橋被占有的時候,就會對 \(x\)~\(n\) 的答案造成 \(1\) 的貢獻。
那么這其實就可以使用樹狀數組來維護。
那么如何預處理呢。
這就是我考場上沒掉的地方,就是一個順序的問題。
因為粗心,考場上並沒有看到這個東西每一個坐標都是獨一無二的。
然后就直接在優先隊列里面按照 \(r\) 排序了。
其實這樣並不是對的,一般的數據都會把我殺死,但是infoj給了我30
所以其實離散化一下每一個位置只有一個變化,這樣使用一個普通的小跟堆就好了。
也確實,當時想要搏一把,20min屬實啥也調不對。
但是沒有打組合拳屬實不應該啊。
菜就是菜了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next.y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
namespace xin
{
int n,m1,m2;
class xin_bit
{
private:
#define low(x) (x & -x)
public:
int c[maxn];
inline void add(int x,int val) {for(;x<=n;x+=low(x)) c[x] += val;}
inline int query(int x) {int ret = 0; for(;x;x-=low(x)) ret += c[x]; return ret;}
}bit1,bit2;
class xin_data
{
public:
int l,r;
xin_data(){}
xin_data(int l,int r):l(l),r(r){}
}d1[maxn],d2[maxn];
int lisan1[maxn],cnt1 = 0,cnt2 = 0;
int lisan2[maxn];
xin_data pos1[maxn],pos2[maxn];
std::priority_queue<int,std::vector<int>,std::greater<int>>q1,q2;
int vis1[maxn],vis2[maxn];
inline short main()
{
io >> n >> m1 >> m2;
try(i,1,m1) io >> d1[i].l >> d1[i].r,lisan1[++cnt1] = d1[i].l,lisan1[++cnt1] = d1[i].r,q1.push(i);
try(i,1,m2) io >> d2[i].l >> d2[i].r,lisan2[++cnt2] = d2[i].l,lisan2[++cnt2] = d2[i].r,q2.push(i);
std::sort(lisan1+1,lisan1+cnt1+1); std::sort(lisan2+1,lisan2+cnt2+1);
try(i,1,m1)
{
d1[i].l = std::lower_bound(lisan1+1,lisan1+cnt1+1,d1[i].l) - lisan1;
d1[i].r = std::lower_bound(lisan1+1,lisan1+cnt1+1,d1[i].r) - lisan1;
pos1[d1[i].l] = xin_data(i,0); pos1[d1[i].r] = xin_data(i,1);
}
try(i,1,m2)
{
d2[i].l = std::lower_bound(lisan2+1,lisan2+cnt2+1,d2[i].l) - lisan2;
d2[i].r = std::lower_bound(lisan2+1,lisan2+cnt2+1,d2[i].r) - lisan2;
pos2[d2[i].l] = xin_data(i,0); pos2[d2[i].r] = xin_data(i,1);
}
// try(i,1,m1) sb(d1[i].l),jb(d1[i].r);
try(i,1,2*m1)
{
if(pos1[i].r == 0) vis1[pos1[i].l] = q1.top(),bit1.add(q1.top(),1),q1.pop();
else q1.push(vis1[pos1[i].l]);//,jb(vis1[pos1[i].l]);
}
try(i,1,2*m2)
{
if(pos2[i].r == 0) vis2[pos2[i].l] = q2.top(),bit2.add(q2.top(),1),q2.pop();
else q2.push(vis2[pos2[i].l]);
}
int ans = 0;
try(i,0,n)
ans = std::max(ans,bit1.query(i) + bit2.query(n-i));
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
[NOIP2014 提高組] 聯合權值
似乎感覺在哪里做過啊。
然后發現確實做過,然后那個是一個改編的題目。
暴力的思路比較一樣,但是實際上正解並不是一樣的。
這個題目首先暴力應該是最差應該只有 \(30pts\),但是沒想到當時 \(CCF\) 的數據那么友善,一直猛給部分分數。
然后我就有 \(70pts\),然后開始考慮正解。
因為我們考慮的是距離為 \(2\) 的,所以一定會有一個中專的點。
但是問題就是知道這個點了怎么做?
考慮最最朴素的算法,也就是暴力算,式子就是:
那么其實就是
所以就可以很快算出來了。
至於最大值,那么其實就是每一個中轉點連接的最大值和次大值的乘積。
之后我總感覺這個的時間復雜度不是很對,但是似乎跑的飛快。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
#define int long long
namespace xin
{
const int mod = 10007;
std::vector<int>vec[maxn/5];
int n;
int w[maxn];
int ans1,ans2;
inline short main()
{
io >> n;
try(i,1,n-1)
{
register int x,y; io >> x >> y;
vec[x].push_back(y); vec[y].push_back(x);
}
try(i,1,n) io >> w[i];
try(i,1,n)
{
int he1 = 0,he2 = 0;
int maxx1 = 0,maxx2 = 0;
for(auto y : vec[i])
{
if(w[y] > maxx1) maxx2 = maxx1,maxx1 = w[y];
else if(w[y] > maxx2) maxx2 = w[y];
he1 += w[y];
(he2 += w[y] * w[y]) %= mod;
}
he1 = he1 * he1 % mod;
ans1 = std::max(ans1,maxx1 * maxx2);
(ans2 += he1 - he2 + mod) %= mod;
}
cout<<ans1<<' '<<ans2<<endl;
return 0;
}
}
signed main() {return xin::main();}
CF702C Cellular Network
就是一個大大大大水題。
然后看錯題目然后調了半天。
生氣。
就是計算每一個的前驅后繼,然后取最小值的最大值就行了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10;
//#define int long long
namespace xin
{
int n,m,ans;
int a[maxn],b[maxn],pi[maxn];
int pai1[maxn],pai2[maxn];
int pos1[maxn],pos2[maxn];
int ner1[maxn],ner2[maxn];
bool vis[maxn];
inline short main()
{
io >> n >> m;
try(i,1,n) io >> a[i]; try(i,1,m) io >> b[i],pai1[i] = pai2[i] = b[i],pai2[i] = -pai2[i];//,jb(pai2[i]);
std::sort(pai1+1,pai1+m+1); std::sort(pai2+1,pai2+m+1);
// jb(std::lower_bound(pai2+1,pai2+m+1,-17) - pai2);
// try(i,1,m) sb(pai1[i]),jb(pai2[i]);
try(i,1,n)
{
pos1[i] = std::lower_bound(pai1+1,pai1+m+1,a[i]) - pai1,pos2[i] = std::lower_bound(pai2+1,pai2+m+1,-a[i]) - pai2;
pos2[i] = m - pos2[i] + 1;
if(!pos1[i] or pos1[i] == m + 1) ans = std::max(ans,abs(a[i] - pai1[pos2[i]]));
else if(!pos2[i] or pos2[i] == m + 1) ans = std::max(ans,abs(a[i] - pai1[pos1[i]]));
else ans = std::max(ans,std::min(abs(a[i] - pai1[pos1[i]]),abs(a[i] - pai1[pos2[i]])));
// sb(pos1[i]); sb(pos2[i]); jb(ans);
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
Day -25
今天又開始聯考了。
開始感覺上來是一個很普通的大水題。。
然后認為線段樹直接就是可以過掉這個題目。
然后發現范圍。。。
淦。
然后開始瘋狂想如何 \(\mathcal O(n)\) 做。
發現是一堆的線段,然后認為可以差分,然而似乎並不知道該如何差分。
但是腦袋當中就一直出現帶着 \(log\) 的做法。
感覺似乎只有 \(60pts\),鑒於csp的經驗,因為時間比較充足,所以打上了對拍
在打 pai.cpp
的時候,突然發現似乎這個暴力的復雜度是均攤一個 \(n\) 的,然后試着證明了一下,發現確實。
然后就反過來了,用着自己的線段樹拍着暴力,發現暴力跑極限只有
\(0.7s\),感覺很好。
開 \(T2\) ,發現手頭沒有小於 \(\mathcal O(n^3)\) 的做法,感覺不是很好。。
然后就寫了一個 \(\mathcal O(n^3)\) 的,然后寫了一個菊花圖的部分分數。
但是如果只要我找到 \(\mathcal O(n^2log)\) 的做法,那么我就可以解決掉鏈的部分和一個詢問的部分。
這樣就有足足 \(80pts\),然而失敗了。
\(T3\) 和 \(T4\) 都是寫了一個極端弱智的部分分數走人了。
然后就是 \(100+45+25+10\)
樹上的數
這個名字似乎像是一個原題,但是完全不是。
做法很簡單,但是不太容易想到去證明這個玩意的復雜度。
並且極端卡常。
我也不知道為啥我這么快
直接每一個詢問進行 \(dfs\),遇到已經貢獻過的就停下來就好了。
只有 \(n\) 個節點,所以一定就是 \(\mathcal O(n)\) 的。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for( int i=a;i<=b;++i)
#define throw(i,a,b) for( int i=a;i>=b;--i)
#define go(i,x) for( signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 5e6+10,inf = 1e9+10;
// #define int long long
namespace xin
{
int n,m;
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],rp;
auto add = [](int x,int y){edge[++rp].ver = y; edge[rp].next = head[x]; head[x] = rp;};
int fa[maxn];
int a,b,he;
int q[maxn],tot,id[maxn],siz[maxn];
bool vis[maxn];
void run(int x)
{
if(!vis[x]) return ;
he += vis[x]; vis[x] = 0;
go(i,x) run(y);
}
inline short main()
{
file(tree);
io >> n >> m;
io >> a >> b;
fa[2] = 1; add(1,2); vis[1] = vis[2] = 1;
try(i,3,n) fa[i] = ((1ll * fa[i - 1] * a + b) ^ 19760817) % (i - 1) + 1,add(fa[i],i),vis[i] = 1;
io >> q[1] >> a >> b;
int ans;
run(q[1]);
ans = n - he;
// sb(siz[q[1]]); jb(he);
try(i,2,m)
{
q[i] = 1ll * (((1ll * q[i - 1] * a + b) ^ 19760817) ^ (i << 1)) % (n - 1) + 2;
run(q[i]);
ans ^= n - he;
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
時代的眼淚
其實這個題目的突破就是 \(\mathcal O(n)\) 的做法。
我們現將權值進行離散化,之后建立權值樹狀數組。
我們先從 \(1\) 節點開始 \(dfs\),之后到達一個節點就變成一個節點的狀態,回溯就好了。
具體就是到達一個節點,然后就將 \(1\) ~ \(w_x-1\) 的下標增加一個 \(1\)。
這就是對下面的點的貢獻。
這樣就能 \(nlog\) 求出來一個的了。
然后的關鍵就是在換根 \(dp\) 上面,我們有一個之后,其他的答案自然就很好從那個來轉移了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10;
#define int long long
namespace xin
{
class xin_edge{public:int next,ver,w;}edge[maxn];
int head[maxn],rp;
inline void add(int x,int y) {edge[++rp].ver = y; edge[rp].next = head[x]; head[x] = rp;}
int n,qnum,w[maxn];
class xin_bit
{
private:
#define low(x) (x & -x)
public:
int c[maxn];
inline void add(int x,int val) {for(;x<=n;x+=low(x)) c[x] += val;}
inline int query(int x) {int ret = 0; for(;x;x-=low(x)) ret += c[x]; return ret;}
}bit;
int lisan[maxn],cnt = 0;
int ret;
int f[maxn],dp[maxn];
void dfs(int x,int fa)
{
bit.add(w[x],1);
int temp = bit.query(w[x]-1),pre = temp;
go(i,x) if(y != fa)
{
dfs(y,x);
int now = bit.query(w[x]-1);
edge[i].w = now - pre; pre = now;
}
f[x] = bit.query(w[x]-1) - temp;
dp[1] += f[x];
// bit.add(w[x]-1,-1);
}
void get_ans(int x,int fa)
{
go(i,x) if(y != fa)
{
dp[y] = dp[x] - edge[i].w + bit.query(w[y]-1) - f[y];
get_ans(y,x);
}
}
inline short main()
{
file(tears);
io >> n >> qnum;
try(i,1,n) io >> w[i],lisan[++cnt] = w[i];
std::sort(lisan+1,lisan+cnt+1);
int k = std::unique(lisan+1,lisan+cnt+1) - (lisan + 1);
try(i,1,n) w[i] = std::lower_bound(lisan+1,lisan+k+1,w[i]) - lisan;
try(i,1,n-1)
{
register int x,y; io >> x >> y;
add(x,y); add(y,x);
}
dfs(1,0);
get_ans(1,0);
try(i,1,qnum)
{
register int x; io >> x;
printf("%lld\n",dp[x]);
}
return 0;
}
}
signed main() {return xin::main();}
傳統藝能
本質不同的子序列的個數的這個東西還是沒有記住啊。
意義就是對於每一個以 \(c\) 結尾的子序列的個數為 \(f_c\),然后這個東西就是表示在每一種字符結尾后面再去接一個新的字符,之后在加上自己一個的新字符就是所有的情況了。
所以這個玩意可以矩陣快速冪
設置三個矩陣,然后修改在線段樹上面修改,注意矩陣不滿足交換律。
1 | |||
---|---|---|---|
1 | 1 | ||
1 | 1 | ||
1 | 1 |
1 | 1 | ||
---|---|---|---|
1 | |||
1 | 1 | ||
1 | 1 |
1 | 1 | ||
---|---|---|---|
1 | 1 | ||
1 | |||
1 |
之后向量的 a[1][1] + a[1][2] + a[1][3]
就是答案了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gec() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scnaf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10;
#define int long long
namespace xin
{
const int mod = 998244353;
char s[maxn],in[10];
int a[maxn],f[maxn];
bool sp = 1;
class xin_mat
{
public:
int a[5][5];
xin_mat(){}
inline void out()
{
try(i,1,4)
{
try(j,1,4)
cout<<a[i][j]<<' ';
cout<<endl;
}
cout<<endl;
}
// xin_mat(int n,int m):n(n),m(m){}
friend xin_mat operator * (const xin_mat &x,const xin_mat &y)
{
xin_mat ret;
// x.out(); y.out();
// try(i,1,4)
// {
// try(j,1,4)
// cout<<x.a[i][j]<<' ';
// cout<<endl;
// }
// try(i,1,4)
// {
// try(j,1,4)
// cout<<y.a[i][j]<<' ';
// cout<<endl;
// }
memset(ret.a,0,sizeof(ret.a));
try(i,1,4) try(j,1,4) try(k,1,4)
(ret.a[i][j] += x.a[i][k] * y.a[k][j]) %= mod;
// jb(ret.a[1][1]);
// try(i,1,4)
// {
// try(j,1,4)
// cout<<ret.a[i][j]<<' ';
// cout<<endl;
// }
return ret;
}
}base,ch[5],vec;
int n,m;
class xin_seg
{
private:
#define ls(fa) (fa << 1)
#define rs(fa) (fa << 1 | 1)
#define up(fa) (t[fa].s = t[ls(fa)].s * t[rs(fa)].s)
public:
class xin_tree{public:xin_mat s;}t[maxn];
void build(int fa,int l,int r)
{
if(l == r) return t[fa].s = ch[a[l]],void();
register int mid = l + r >> 1;
build(ls(fa),l,mid); build(rs(fa),mid+1,r);
up(fa);
// t[fa].s.out();
}
void upd(int fa,int l,int r,int pos,int val)
{
if(l == r) return t[fa].s = ch[val],void();
register int mid = l + r >> 1;
if(pos <= mid) upd(ls(fa),l,mid,pos,val);
else upd(rs(fa),mid+1,r,pos,val);
up(fa);
}
xin_mat query(int fa,int l,int r,int ql,int qr)
{
if(ql <= l and qr >= r) return t[fa].s;
register int mid = l + r >> 1,ok = 0; xin_mat ret;
if(ql <= mid) ret = query(ls(fa),l,mid,ql,qr),ok = 1;
if(qr > mid)
{
if(ok) ret = ret * query(rs(fa),mid+1,r,ql,qr);
else ret = query(rs(fa),mid+1,r,ql,qr);
}
return ret;
}
}t;
inline void init()
{
try(i,1,3) memset(ch[i].a,0,sizeof(ch[i].a));
// ch[1] = ch[2] = ch[3] = xin_mat(4,4);
ch[1].a[1][1] = ch[1].a[2][1] = ch[1].a[3][1] = ch[1].a[4][1] = ch[1].a[2][2] = ch[1].a[3][3] = ch[1].a[4][4] = 1;
ch[2].a[1][1] = ch[2].a[1][2] = ch[2].a[2][2] = ch[2].a[3][2] = ch[2].a[3][3] = ch[2].a[4][2] = ch[2].a[4][4] = 1;
ch[3].a[1][1] = ch[3].a[2][2] = ch[3].a[3][3] = ch[3].a[4][4] = ch[3].a[1][3] = ch[3].a[2][3] = ch[3].a[4][3] = 1;
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(string);
#endif
io >> n >> m;
scanf("%s",s+1);
try(i,1,n)
{
a[i] = s[i] - 'A' + 1;
if(a[i] != 1) sp = 0;
}
memset(base.a,0,sizeof(base.a)); memset(vec.a,0,sizeof(vec.a));
try(i,1,4) base.a[i][i] = 1;
vec.a[1][4] = 1;
init();
// try(cse,1,3)
// {
// try(i,1,4)
// {
// try(j,1,4)
// cout<<ch[cse].a[i][j]<<' ';
// cout<<endl;
// }
// cout<<endl;
// }
t.build(1,1,n);
try(cse,1,m)
{
register int op; io >> op;
if(op == 1)
{
register int x; io >> x;
char in[10]; scanf("%s",in+1);
a[x] = in[1] - 'A' + 1;
t.upd(1,1,n,x,a[x]);
}
else
{
register int l,r; io >> l >> r;
xin_mat ret = t.query(1,1,n,l,r),temp = vec;
temp = temp * ret;
printf("%lld\n",(temp.a[1][1] + temp.a[1][2] + temp.a[1][3]) % mod);
}
}
return 0;
}
}
signed main() {return xin::main();}
鋪設道路
貪心。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10;
#define int long long
namespace xin
{
const int mod = 1e9+7;
std::queue<int>q;
std::stack<int>st;
int n,a[maxn],b[maxn];
int ans1,ans2,ans;
inline short main()
{
#ifdef ONLINE_JUDGE
file(road);
#endif
io >> n;
try(i,1,n) io >> a[i];
try(i,1,n+1) b[i] = a[i] - a[i-1],ans += (b[i] > 0) ? b[i] : 0;
try(i,1,n+1)
{
if(b[i] > 0) q.push(i);
else
{
while(b[i] < 0)
{
register int x = q.front();
if(abs(b[x]) <= abs(b[i]))
{
b[i] += b[x];
ans1 = (ans1 + (i - x) * (i - x) % mod * b[x] % mod) % mod;
q.pop();
}
else
{
b[x] += b[i];
ans1 = (ans1 + (i - x) * (i - x) % mod * (-b[i]) % mod) % mod;
b[i] = 0;
}
}
}
}
try(i,1,n+1) b[i] = a[i] - a[i-1];
try(i,1,n+1)
{
if(b[i] > 0) st.push(i);
else
{
while(b[i] < 0)
{
register int x = st.top();
if(abs(b[x]) < abs(b[i]))
{
b[i] += b[x];
ans2 = (ans2 + (i - x) * (i - x) % mod * b[x] % mod) % mod;
st.pop();
}
else
{
b[x] += b[i];
ans2 = (ans2 + (i - x) * (i - x) % mod * (-b[i]) % mod) % mod;
b[i] = 0;
}
}
}
}
cout<<ans<<endl<<ans2<<endl<<ans1<<endl;
return 0;
}
}
signed main() {return xin::main();}
Day -24
昨天在做 \(T2\) 的時候,發現自己的樹狀數組的理解是偏差的。
所以就重新學了一遍樹狀數組,發現其實樹狀數組的基本是單點修改,區間查詢
我一直認為是區間修改,單點查詢啊。。
只不過區間修改可以使用差分來解決。
樹狀數組還有一個強大的用處,就是進行區間修改,區間查詢
感覺很強,實際更強。
無論是空間上面還是時間上面又要優過線段樹。
這個其實也是一個差分的過程。
所以就可以維護兩個差分的數組,然后在查詢的時候 (p + 1) * c1[i] - c2[i]
就好了。
code
class xin_bit
{
private:
#define low(x) (x & -x)
public:
int c1[maxn],c2[maxn];
inline void add(int x,int val)
{
for(int i=x;i<=n;i+=low(i)) c1[i] += val,c2[i] += x * val;
}
inline void upd(int l,int r,int val) {add(l,val); add(r+1,-val);}
inline int ask(int x)
{
int ret = 0;
for(int i=x;i;i-=low(i))
ret += (x + 1) * c1[i] - c2[i];
return ret;
}
inline int query(int l,int r) {return ask(r) - ask(l-1);}
}bit;
還是很快的。
然后開始考試啊。
幾天的考試頗有幾番不順利。
上來的思路感覺修正很對,然后飛速寫完,一下子過了小樣例。
然后測大樣例。。。
發現兩百個里面有兩個是不一樣的,心態稍炸。
然后瘋狂調試,發現做法是假的,但是認為 \(q=1\) 的點是可以過去的。
所以就放下了。
然后開始做 \(T2\),然后認為很垃圾的一個題目。
然后。。。
小樣例又過了。
大樣例。。。還是錯兩個??!!
然后又沒了。
最后兩個題目的 \(pretask\) 都沒有過掉。。。
然后后面兩個題目的東西的暴力瘋狂挼了一下。
然后。。。\(30+20+20=70\)
垃圾分數。
寶藏
首先我們要分析出一個很妙的性質,就是說這個的答案是隨 \(x\) 的增大而減小的。
那么就可以二分出來答案。
提前兩種的排序,然后就是 \(qnlogn\) 的復雜度
如果仔細的話,你會發現這個子任務 \(2\) 並沒有給 \(Q\) 的范圍。
是不是他忘了呢???
不是,這個真的就是 \(3*10^5\)
所以這個東西只有 \(50pts\) 。
我們考慮正解,我們回想自己在 \(check\) 的過程中,我們分開左邊和右邊。
我們會分別對左右進行排序。
那么我們不妨把每一種答案都預處理出來,因為對於相鄰的詢問,變化還是比較小的。
所以兩邊就可以維護一個 \(set\),之后就可以 \(log\) 轉移。
然后我才知道平常一直不讓用的關鍵字 next
這個函數的用法
我們維護 \(ls,rs,mid1,mid2\) 分別表示左邊的時間和,右邊的時間和,還有左邊中間的,右邊中間的。
之后就能轉移到我們想要的答案了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
class xin_data
{
private:
friend bool operator < (xin_data x,xin_data y)
{
if(x.tim xor y.tim) return x.tim < y.tim;
return x.id < y.id;
}
friend bool operator <= (xin_data x,xin_data y)
{
if(x.tim xor y.tim) return x.tim < y.tim;
return x.id <= y.id;
}
public:
int val,tim,id;
xin_data(){}
xin_data(int val,int tim,int id):val(val),tim(tim),id(id){}
}d[maxn];
int n,qnum,t;
std::set<xin_data>s1,s2;
xin_data mid1,mid2;
int ans[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(treasure);
#endif
io >> n >> t >> qnum;
try(i,1,n) io >> d[i].val >> d[i].tim,d[i].id = i;
std::sort(d+1,d+n+1,[](xin_data x,xin_data y){return (x.val == y.val) ? x.id < y.id : x.val < y.val;});
try(i,1,n-1) s1.insert(d[i]);
s1.insert(mid1); s2.insert(mid2);
int ls = 0,rs = 0,zhi = n;
bool ok = 0;
for(int i=1;i<=n;i+=2)
{
if(ok) {ans[i] = -1; continue;}
while(ls + rs + d[zhi].tim > t and zhi)
{
s2.insert(d[zhi]);
auto it = s2.find(mid2);
if(d[zhi] <= mid2) rs += d[zhi].tim - mid2.tim,mid2 = *--it;
zhi --;
it = s1.find(mid1);
if(d[zhi] <= mid1)
{
if(++it != s1.end()) mid1 = *it;
else {ok = 1; break;}
ls += mid1.tim - d[zhi].tim;
}
s1.erase(d[zhi]);
}
ans[i] = d[zhi].val;
if(ok) {ans[i] = -1; continue;}
auto it = s2.find(mid2);
if(++it == s2.end())
{
s2.insert(d[zhi]);
auto it = s2.find(mid2);
if(d[zhi] <= mid2) rs += d[zhi].tim - mid2.tim,mid2 = *--it;
zhi --;
it = s1.find(mid1);
if(d[zhi] <= mid1)
{
if(++it != s1.end()) mid1 = *it;
else {ok = 1; break;}
ls += mid1.tim - d[zhi].tim;
}
s1.erase(d[zhi]);
}
it = s2.find(mid2); mid2 = *next(it),rs += mid2.tim;
it = s1.find(mid1); if(next(it) != s1.end()) mid1 = *next(it),ls += mid1.tim; else ok = 1;
}
try(cse,1,qnum)
{
register int x; io >> x;
printf("%lld\n",ans[x]);
}
return 0;
}
}
signed main() {return xin::main();}
尋找道路
考場上面想到了正解,但是因為細節沒有調出來。。。
這個題目實際上就是一個廣搜,是一個分布廣搜這個是我自己起的名字。。。
然后注意 \(0\) 和 \(1\) 的轉移順序,這樣的話隊列的第一個一定就是最優的答案。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int mod = 1e9+7;
class xin_edge{public:int next,ver,w;}edge[maxn];
int head[maxn],rp;
inline void add(int x,int y,int z){edge[++rp].ver = y; edge[rp].next = head[x];edge[rp].w = z; head[x] = rp;}
int n,m;
bool vis[maxn];
int a[maxn],b[maxn];
std::vector<int>ans[maxn/10],vec;
class xin_data
{
public:
int x,tim;
xin_data(){}
xin_data(int x,int tim):x(x),tim(tim){}
};
int dis[maxn],d[maxn];
std::queue<int>q;
void dfs(int x)
{
vis[x] = 1; q.push(x); dis[x] = 0;
go(i,x) if(!vis[y] and !edge[i].w) dfs(y);
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(path);
#endif
io >> n >> m;
try(i,1,m)
{
register int x,y,z; io >> x >> y >> z;
add(x,y,z);
}
memset(dis,-1,sizeof(int) * (n + 1));
dfs(1);
// debug;
int now1,now2;
while(q.size())
{
int zhi = 0; now1 = d[q.front()]; now2 = dis[q.front()];
while(q.size() and d[q.front()] == now1 and dis[q.front()] == now2) a[++zhi] = q.front(),q.pop();
try(i,1,zhi)
{
int x = a[i];
go(i,x) if(!vis[y] and !edge[i].w)
{
d[y] = d[x] + 1;
dis[y] = dis[x] * 2 % mod;
q.push(y); vis[y] = 1;
}
}
try(i,1,zhi)
{
int x = a[i];
go(i,x) if(!vis[y] and edge[i].w)
{
d[y] = d[x] + 1;
dis[y] = (dis[x] * 2 + 1) % mod;
q.push(y); vis[y] = 1;
}
}
}
try(i,2,n) printf("%lld ",dis[i]);
return 0;
}
}
signed main() {return xin::main();}
考試總結
這場考試實際上做的很差,在時間分配問題上還有很大的問題,主要在第一個題目上面的用時其實還是不夠,總是感覺會影響后面的題目,但是其實只有第一個題目和第二個題目是比較可做的。
其實應該敢用時間在讀題目上面,可以開始的時候先把左右的題目通讀一遍,之后可以根據估計的難度進行時間的分配,可以先把認為非常不可做的題目的暴力打完,這樣心里面就沒有了負擔。
之后再去花費比較大量的時間在自己有可能做出來的題目上面。
這樣就能將自己會做的題目盡可能的拿上最多的分數了。
Day -23
今天剛上來就有一個口胡比賽,結果一番口胡正解。。。
紅黑樹
首先這個每一次的操作永遠是以顏色相同的聯通塊為前提的。
所以我們看這個樹的最小單位就應該是一個一個的聯通塊。
那么就可以開始縮點,把顏色相同的聯通塊縮成一個點。
之后考慮如何將這個樹以最小的操作數量變成一個顏色。
現在的樹上的節點每一個都是互不相同的,也就是每隔一個一種顏色。
假設現在是一個這樣的樹(縮點之后的樹),那么這個樹的最長的鏈就是 \(15...1...3...........9...10\) 這個鏈。
假設我們首先沒有操作這個直徑上面的節點。
那么直徑上面一定還會留下沒有被操作過的節點需要被操作。
這樣的操作數量一定不會比直徑的長度的二分之一要小。
如果我們直接對於直徑每隔一個節點進行操作。
那么因為直徑無論在哪一個節點后面都是不短的,那么其他所有的子樹一定也會在直徑操作結束之前被操作完成。
所以答案一定也就是(直徑+1)/2
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10;
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],zhi;
inline void add(int x,int y) {edge[++zhi].ver = y ;edge[zhi].next= head[x]; head[x] = zhi;}
class xin_data{public:int x,y;}d[maxn];
class xin_tim
{
public:
int x,tim;
xin_tim(){}
xin_tim(int x,int tim):x(x),tim(tim){}
};
int a[maxn],n;
int fa[maxn];
int biao[maxn],tot;
bool vis[maxn];
inline int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
void dfs(int x,int f)
{
go(i,x) if(y != f)
{
dfs(y,x);
if(a[y] == a[x]) fa[find(x)] = find(y);
}
}
inline short main()
{
io >> n;
try(i,1,n) io >> a[i],fa[i] = i;
try(i,1,n-1)
{
io >> d[i].x >> d[i].y;
// add(x,y); add(y,x);
add(d[i].x,d[i].y); add(d[i].y,d[i].x);
}
dfs(1,0);
// try(i,1,n) sb(i),jb(find(i));
try(i,1,n)
{
int fx = find(i);
if(!vis[fx])
{
vis[fx] = 1;
biao[fx] = ++tot;
}
}
// try(i,1,n) sb(i),jb(biao[find(i)]);
memset(head,0,sizeof(int) * (n + 1)); zhi = 0;
try(i,1,n-1)
{
int fx = find(d[i].x),fy = find(d[i].y);
if(fx xor fy) add(biao[fx],biao[fy]),add(biao[fy],biao[fx]);//,cout<<(biao[fy])<<' '<<(biao[fx])<<endl;
}
std::queue<xin_tim>q; q.push(xin_tim(1,0)); int pot,now = 0;
memset(vis,0,sizeof(bool) * (n + 1));vis[1] = 1;
while(q.size())
{
xin_tim x = q.front(); q.pop();
// sb(x.tim);jb(x.x);
if(x.tim > now) now = x.tim,pot = x.x;
go(i,x.x) if(!vis[y])
{
vis[y] = 1; q.push(xin_tim(y,x.tim+1));
}
}
// jb(pot);
// jb(now);
q.push(xin_tim(pot,0)); now = 0;
memset(vis,0,sizeof(bool ) * (n + 1)); vis[pot] = 1;
while(q.size())
{
xin_tim x = q.front(); q.pop();
if(x.tim > now) now = x.tim;
go(i,x.x) if(!vis[y]) vis[y] = 1,q.push(xin_tim(y,x.tim+1));
}
// jb(now);
// if(now == 1) cout<<0<<endl;
cout<<(now+1)/2<<endl;
return 0;
}
}
signed main() {return xin::main();}
話說我好像把昨天寫的丟了。。
Day -22
我記錯了。。。
Day -21
話說為什么昨天還是-23
似乎我從剛開始就記錯了。。。
今天還是有模擬賽的一天,沒有什么口胡比賽。。
並且還是毒瘤出題人 \(JKLover\) 的sb好題
莓良心
這個其中很關鍵的一步就是求集合的划分。
這個需要用到第二類斯特林數
但是這個東西到考場上卻忘記了怎么推了。。
這個就是方案就是斯特林嘛。。
那怎么求呢??
。。。。。
順帶復習一下子。
\(\begin {Bmatrix} n \\ m\end {Bmatrix}\) 就表示有 \(n\) 個數,划分為 \(k\) 個非空子集的方案數。
那么這個東西如何在小於 xin_team
的時間復雜度求出呢??
首先有一個 \(n^2\) 的遞推。
然后初值就是 \(\begin {Bmatrix} n \\ 0 \end {Bmatrix}=[n=0]\)
當然還有通項公式:
似乎是通過一個容斥得出的。
只不過這玩意是 \(nlog\) 的。。
還有一個性質,似乎感覺自己也是背不過。。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define debug std::cerr<<"debug"<<endl
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define scanf ak = scank
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10;
#define int long long
namespace xin
{
const int mod = 998244353;
int a[maxn];
int n,k;
int he;
int s1,s2;
int fac[maxn],inv[maxn];
auto C = [](int n,int m) {return fac[n] * inv[m] % mod * inv[n-m] % mod;};
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod;y >>= 1;
}
return ret;
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(ichigo);
#endif
io >> n >> k;
try(i,1,n) io >> a[i],he += a[i],he %= mod;
fac[0] = inv[0] = 1;
try(i,1,k) fac[i] = fac[i-1] * i % mod;
inv[k] = ksm(fac[k],mod-2);
throw(i,k-1,1) inv[i] = inv[i+1] * (i + 1) % mod;
// jb(C(2,1));
int base = 1;
try(i,0,k)
{
(s1 += base * C(k,i) % mod * ksm(k-i,n) % mod + mod) %= mod;
// jb(s1);
(s2 += base * C(k,i) % mod * ksm(k-i,n-1) % mod + mod) %= mod;
// jb(s2);
base = -base;
}
// jb(s1); jb(s2);
cout<<he * ((s1 + (n - 1) * s2 % mod) % mod) % mod * inv[k] % mod<<endl;
return 0;
}
}
signed main() {return xin::main();}
``
</details>
**盡梨了**
這個主要的問題還是在 $dp$ 上面,如果沒有進行排序,那么這個需要的 $dp$ 就會是從這些集合當中不重復的選擇。
似乎這個只有背包可以完成,但是體積直接達到了 $10^9$
所以正確的解法應該是消除一個的限制。
我們首先明確哪個順序一定是優的。
之后再進行 $dp$ 才可。
<details>
<summary>code</summary>
```cpp
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
class xin_data
{
public:
int x,y;
xin_data(){}
xin_data(int x,int y):x(x),y(y){}
}d[maxn];
int a[maxn];
int n,tim;
int cnt1,cnt2;
int f[maxn][33];
inline bool comp(const xin_data &x,const xin_data &y) {return x.y * y.x < x.x * y.y;}
inline short main()
{
#ifdef ONLINE_JUDGE
file(eriri);
#endif
io >> n >> tim;
try(i,1,n)
{
register int x,y; io >> x >> y; y += x + 1;
if(!x) a[++cnt2] = y;
else d[++cnt1] = xin_data(x,y);
}
std::sort(d+1,d+cnt1+1,comp); std::sort(a+1,a+cnt2+1);
memset(f,0x3f,sizeof(f)); f[0][0] = 0;
// try(i,1,cnt1) sb(d[i].x),jb(d[i].y);
try(i,0,cnt1-1) try(j,0,32) if(f[i][j] <= tim)
{
f[i+1][j] = std::min(f[i+1][j],f[i][j]);
int temp = (f[i][j] + 1) * (d[i+1].x + 1) + (d[i+1].y - d[i+1].x - 1);
// jb(temp);
if(temp <= tim) f[i+1][j+1] = std::min(f[i+1][j+1],temp);
}
int pos = 0,ans = 0,he = 0;
throw(i,32,0) if(f[cnt1][i] <= tim)
{
while(pos != cnt2 and he + f[cnt1][i] + a[pos+1] <= tim)
he += a[++pos];
ans = std::max(ans,pos + i);
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
團不過
考慮在限定每堆石子數目互不相同的前提下,用所有方案數減去先手必敗的方
案數。
設 \(p(i) = (2n −1)^{\underline i}\) ,即 \(i\) 堆石子的總方案數。
設 \(f(i)\) 表示 \(i\) 堆石子時先手必敗的方案數。
我們考慮讓前 \(i −1\) 堆石子任意取,通過調整最后一堆石子的數目使得異或和為\(0\) ,方案數為 \(p(i −1)\) 。
若前 \(i −1\) 堆石子異或和為 \(0\) ,因為最后一堆不能取 \(0\) ,這種情況是不合法的,
方案數為 \(f(i −1)\) 。
若前 \(i −1\) 堆石子中,有 \(i −2\) 堆石子異或起來是 \(0\) ,那么最后一堆石子就只能
和另一堆石子數目相同,也是不合法的,方案數為 \((i −1) ·(2n −i + 1) ·f(i −2)\) 。
於是得到 \(f(i) = p(i −1) −f(i −1) −(i −1) ·(2n −i + 1) ·f(i −2)\) ,邊界為
\(f(1) = f(2) = 0\) ,直接 \(\mathcal O(n)\) 遞推即可
關於下降冪。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int mod = 1e9+7;
int f[maxn],fac[maxn],inv[maxn],n,p[maxn];
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(yui);
#endif
io >> n;
fac[0] = inv[0] = 1; int pow2 = ksm(2,n);
try(i,1,n) fac[i] = fac[i-1] * i % mod;
p[1] = pow2 - 1;
try(i,2,n) p[i] = p[i-1] * (pow2 - i) % mod;
inv[n] = ksm(fac[n],mod-2);
throw(i,n-1,1) inv[i] = inv[i+1] * (i + 1) % mod;
// jb(p(2));
// return 0;
try(i,3,n) f[i] = (p[i-1] - f[i-1] - (i - 1) * (pow2 - i + 1) % mod * f[i-2] % mod + mod) % mod;
cout<<(p[n] - f[n] + mod) % mod <<endl;
return 0;
}
}
signed main() {return xin::main();}
七負我
這個有一個結論。
就是這個題目我們要找到圖中的最大團。
然后平均分配就是答案。
忘了怎么證明的了。
然后狀態壓縮一下,之后 \(meet\;in\;middle\) 就好了
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
inline void out(int x)
{
cout<<"x = ";
int st = 0;
throw(i,30,1) if(x & (1 << i - 1)) {st = i; break;}
throw(i,st,1) cout<<(bool)(x & (1 << i - 1));
cout<<endl;
}
int f[maxn];
int n,m,tim;
int a[maxn],cnt[maxn];
auto get = [](int x)
{
int ret = 0;
while(x) ret += x & 1,x >>= 1;
return ret;
};
inline short main()
{
#ifdef ONLINE_JUDGE
file(nanami);
#endif
io >> n >> m >> tim;
a[1] = 1; try(i,2,40) a[i] = a[i-1] << 1;//,out(a[i]);
int mid = (n + 1) >> 1;
try(i,1,m)
{
register int x,y; io >> x >> y;
a[x] |= 1ll << y - 1; a[y] |= 1ll << x - 1;
}
// try(i,1,3) out(a[i]);
try(s,1,(1 << mid)) cnt[s] = get(s);
try(s,1,(1 << mid) - 1)
{
// int num = 0;
int temp = -1;
try(i,1,mid) if(s & (1 << i - 1)) f[s] = std::max(f[s],f[s xor (1 << i - 1)]),temp &= a[i];
// out(temp);
// jb(cnt[s]);
if((s & temp) == s) f[s] = cnt[s];
// sb(s); jb(f[s]);
}
int ms = n - mid,ans = 0;
try(s,1,(1 << ms) - 1)
{
int temp = -1;
try(i,1,ms) if(s & (1 << i - 1)) temp &= a[i+mid];
// jb(cnt[s]);
// jb(temp);
if((temp & (s << mid)) == (s << mid))
ans = std::max(ans,cnt[s] + f[temp & (1ll << mid) - 1]);//,jb(temp),jb(mid);
}
// jb(ans);
printf("%.6lf\n",(1.0 * tim / ans) * (1.0 * tim / ans) * (ans * (ans - 1)) * 0.5);
return 0;
}
}
signed main() {return xin::main();}
所以這個題目的難處就是在求這個圖的最大團上面了。
然而似乎這個問題是 \(NP\) 完全的。
Day -20
;
話說我為啥老是丟掉之前寫的博客啊。。
還是模擬賽日。
然后拿了倒數
特殊字符串
首先上來的 \(dp\) 一看沒有小樣例,直接就跳過了。
然后發現。。
一共。。。
\(68\) 人寫過。。
然后我。。
為啥沒有去再看看呢
其實就是直接 \(dp\)。
我們設 \(f_{i,j}\) 表示前 \(i\) 個串結尾強制為 \(j\) 這個字母的映射的答案。
那么直接就是
\(a_{k,j}\) 就是輸入的貢獻。
然后呢。。。
沒了。。
我也沒了。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,two = 2e3+10,inf = 1e9+10;
#define int long long
namespace xin
{
int a[27][27];
int f[maxn][27];
int n;
char s[maxn];
char s1[maxn],s2[maxn];
inline short main()
{
freopen("shiki.in","r",stdin); freopen("shiki.out","w",stdout);
io >> n;
scanf("%s",s+1);
int m; io >> m;
try(i,1,m)
{
int k;
scanf("%s%s",s1+1,s2+1); io >> k;
a[s1[1] - 'a' + 1][s2[1] - 'a' + 1] += k;
}
int ans = 0;
memset(f,128,sizeof(f));
// jb(f[1][1]);
try(i,1,n)
{
int j = s[i] - 'a' + 1;
f[i][j] = 0;
try(k,1,26)
f[i][j] = std::max(f[i][j],f[i-1][k] + a[k][j]),f[i][k] = std::max(f[i][k],f[i-1][k]);
ans = std::max(f[i][j],ans);
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
寶可夢
別問我為啥對 pokemon
有一種特殊的情結。
所以我上來就做這個題了。
剛上來發現這個題目是一個大模擬,然后認為需要投入很長的時間。
然后瘋狂開始碼,然后半個小時寫完了。
然后發現這個有一個 \(n=2\) 的部分分數,然后想到了似乎這個只有一條路徑。
但是為啥我沒有推廣一下子呢,其實所有的圖都是只有一條路徑的啊。
暴力的想法其實就是每次給出的兩個坐標都模擬一遍。
但是這樣只有垃圾的 \(40pts\)。
因為每一個空閑點一定會被走過至少一次,那么我們可以任意找到一個空白點,之后試探四個方向哪個可以開始走,這樣我們就找到了其中的一個點了。
從這個點開始,我們一定可以走完這個圖中唯一的道路,這樣我們記錄一下坐標和它的方向,然后記錄走到這個位置的相對時間。
對於每一次詢問,做一下差就行了,只不過要注意一下方向等細節。
然后我獲得了次垃解
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gec() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<22,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scanf ak = scanf
char buf[1<<22],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,two = 2e3+10,inf = 1e9+10;
// #define int long long
namespace xin
{
int n,m;
std::vector<int> a[maxn/2];
char s[maxn];
class xin_data
{
public:
int x,y;
xin_data(){}
xin_data(int x,int y):x(x),y(y){}
};
auto you = [](const xin_data &x,int type)
{
if(type == 1) return xin_data(x.x,x.y+1);
else if(type == 2) return xin_data(x.x,x.y-1);
else if(type == 3) return xin_data(x.x-1,x.y);
else return xin_data(x.x+1,x.y);
};
auto qian = [](const xin_data &x,int type)
{
if(type == 1) return xin_data(x.x-1,x.y);
else if(type == 2) return xin_data(x.x+1,x.y);
else if(type == 3) return xin_data(x.x,x.y-1);
else return xin_data(x.x,x.y+1);
};
inline int get(char ch)
{
if(ch == 'U') return 1;
else if(ch == 'D') return 2;
else if(ch == 'L') return 3;
else return 4;
}
auto zz = [](int type)
{
if(type == 1) return 3;
else if(type == 2) return 4;
else if(type == 3) return 2;
else return 1;
};
auto yz = [](int type)
{
if(type == 1) return 4;
else if(type == 2) return 3;
else if(type == 3) return 1;
else return 2;
};
class xin_map
{
private:
friend bool operator < (const xin_map &x,const xin_map &y)
{
if(x.x xor y.x) return x.x < y.x;
if(x.y xor y.y) return x.y < y.y;
return x.nt < y.nt;
}
public:
int x,y,nt;
xin_map(){}
xin_map(int x,int y,int nt):x(x),y(y),nt(nt){}
};
std::map<xin_map,int>vis;
auto query = [](xin_data now,xin_data goal,char type)
{
int ret = 0,nt = get(type),gt = nt;
xin_data pre = xin_data(0,0);
now = qian(now,nt); ret ++;
vis[xin_map(now.x,now.y,nt)] = ret;
while(now.x != goal.x or now.y != goal.y or nt != gt)
{
// vis[xin_map(now.x,now.y,nt)] = ret;
// sb(now.x); sb(now.y); jb(ret);
if(!a[you(now,nt).x][you(now,nt).y])
{
while(!a[qian(now,nt).x][qian(now,nt).y])
{
if(now.x == goal.x and now.y == goal.y and nt == gt) return ret;
nt = zz(nt);
if(now.x == goal.x and now.y == goal.y and nt == gt) return ret;
}
now = qian(now,nt); ret ++;
vis[xin_map(now.x,now.y,nt)] = ret;
}
else
{
now = you(now,nt); ret ++;
nt = yz(nt);
vis[xin_map(now.x,now.y,nt)] = ret;
}
}
return ret;
};
inline char get_alpha(int x)
{
if(x == 1) return 'U';
else if(x == 2) return 'D';
else if(x == 3) return 'L';
else return 'R';
}
inline void init(int &tot)
{
try(i,1,n) try(j,1,m)
{
try(t,1,4)
{
if(a[i][j] and a[qian(xin_data(i,j),t).x][qian(xin_data(i,j),t).y])
{
// debug;
tot = query(xin_data(i,j),xin_data(i,j),get_alpha(t));
// ok = 1;
return;
}
}
}
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(pokemon);
#endif
scanf("%d%d",&n,&m);
try(i,1,m) a[0].emplace_back(0),a[n+1].emplace_back(0);
try(i,1,n)
{
a[i].emplace_back(0);
scanf("%s",s+1);
try(j,1,m) a[i].emplace_back((s[j] == '.'));//,cout<<a[i][j];
a[i].emplace_back(0);
a[i].reserve(m + 10);
// cout<<endl;
}
int qnum; scanf("%d",&qnum);
int tot; init(tot);
// jb(query(xin_data(1,1),xin_data(1,1),'R'));
// jb(tot);
// try(i,1,n) {try(j,1,m) cout<<std::setw(4)<<vis[xin_map(i,j,1)]; cout<<endl;}cout<<endl;
// try(i,1,n) {try(j,1,m) cout<<std::setw(4)<<vis[xin_map(i,j,2)]; cout<<endl;}cout<<endl;
// try(i,1,n) {try(j,1,m) cout<<std::setw(4)<<vis[xin_map(i,j,3)]; cout<<endl;}cout<<endl;
// try(i,1,n) {try(j,1,m) cout<<std::setw(4)<<vis[xin_map(i,j,4)]; cout<<endl;}cout<<endl;
try(cse,1,qnum)
{
register int x,y,goalx,goaly;
scanf("%d%d%d%d%s",&x,&y,&goalx,&goaly,s+1);
if(x == goalx and y == goaly) {puts("0"); continue;}
int ans = inf;
try(i,1,4)
if(vis[xin_map(goalx,goaly,i)])
{
int temp = (vis[xin_map(goalx,goaly,i)] - vis[xin_map(qian(xin_data(x,y),get(s[1])).x,qian(xin_data(x,y),get(s[1])).y,get(s[1]))]);
// jb(temp);
if(temp < 0) temp += tot;
ans = std::min(ans,temp + 1);
}
if(ans < 0) ans += tot;
printf("%d\n",ans);
// cout<<ans<<endl;
// sb(vis[xin_map(goalx,goaly,1)]); jb(vis[xin_map(x,y,get(s[1]))]);
// printf("%d\n",vis[xin_map(goalx,goaly,4)] - vis[xin_map(x,y,get(s[1]))]);
// printf("%d\n",query(xin_data(x,y),xin_data(goalx,goaly),s[1]));
}
return 0;
}
}
signed main() {return xin::main();}
矩陣
直接搜索就行,因為大概率搜不下去。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<22,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define debug std::cerr<<"debug"<<endl
char buf[1<<22],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,two = 2e3+10,inf = 1e9+10;
// #define int long long
namespace xin
{
const int dx[] = {0,0,-1,1},dy[] = {1,-1,0,0};
int *a[40002];
int n,m;
bool sp = 1;
class xin_data
{
public:
int x,y,bei,tim;
xin_data(){}
xin_data(int x,int y,int bei = 0,int tim = 0):x(x),y(y),bei(bei),tim(tim){}
}q[maxn];
int zhi = 0,ans,cnt;
void bfs(const xin_data &now)
{
q[zhi = 1] = now;
int ms = 1e7;
while(zhi)
{
xin_data x = q[zhi--];
if(cnt >= ms) {cout<<(1<<4)<<endl; exit(0);}
try(i,0,3)
{
xin_data p = xin_data(x.x + dx[i],x.y + dy[i]);
if(p.x >= 1 and p.x <= n and p.y >= 1 and p.y <= m)
{
++cnt;
if(a[p.x][p.y] % a[x.x][x.y] == 0 and (!x.bei or (x.bei and a[p.x][p.y] / a[x.x][x.y] == x.bei)))
{
q[++zhi] = xin_data(p.x,p.y,a[p.x][p.y] / a[x.x][x.y],x.tim + 1);
// jb(x.tim + 2);
ans = std::max(ans,x.tim + 2);
}
}
}
}
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(matrix);
#endif
io >> n >> m;
if(n == 1 and m == 1) return puts("1"),0;
// if(n >= 5000) return cout<<10<<endl,0;
// try(i,0,m+1) a[0].emplace_back(0),a[n+1].emplace_back(0);
a[0] = new int [m + 2]; a[n+1] = new int [m + 2];
try(i,1,n)
{
a[i] = new int [m + 2];
try(j,1,m)
{
int x; io >> x; a[i][j] = x;
// if(j - 1 and a[i][j] != a[i][j-1]) sp = 0;
if((i - 1 and a[i][j] == a[i-1][j]) or (j - 1 and a[i][j] == a[i][j-1]))
return puts("-1"),0;
}
// a[i].emplace_back(0);
// a[i].reserve(m + 10);
}
// if(sp) {puts("-1"); return 0;}
try(i,1,n) try(j,1,m) bfs(xin_data(i,j));
jb(cnt);
cout<<std::max(ans,1)<<endl;
return 0;
}
}
signed main() {return xin::main();}
乘法
別問,問就是做不出來。
但是這個題目的分段打表屬實漲知識了。
可以拿到 \(30pts\) 的高分。
但是為啥我的暴力沒有一點分呢。。。
下午5:10
教練:一會兒可以出去玩兒會兒。
然后開始乒乓球頹廢生活。
fengwu:我要打爆七百信。
然后。。。
fengwu
自閉。
晚上8:00
太虛:出分了。
機房嘩然,然后開始查分。
發現沈隊一旁鎮定地查分,絲毫不慌。
再怎么掛也是HE rk1
然后土豆服務器被擠爆了,幾乎沒有幾個人能夠上去。
之后搖擺b首先查到分數,然后他第一個題目的 \(40pts\) 被 \(CCF\) 的數據抬到了 \(60pts\)。
表示羡慕。
之后終於看到分數,發現自己四處爆零的廊橋分配竟然有 \(55pts\),突然開始感謝 \(CCF.jpg\)
四處爆零
話說沈隊真的是 \(360pts\)
Day -19
今天並沒有模擬賽。
昨天看的垃圾 \(dp\) 守望者的逃離今天決定扔掉。
因為沒有一個題解寫的 \(dp\)
做了一個教主的花園
教主的花園
以為是區間 \(dp\),但是似乎並不能用區間 \(dp\) 轉移。
首先如果不考慮這個是一個環的話,那么我們直接可以從 \(1\) 推到 \(n\)。
那這樣該怎么列 \(dp\) 方程呢。
我們設 \(f_{i,0/1/2,0/1}\) 分別表示前 \(i\) 個,第 \(i\) 個選擇了哪種樹苗,之后是否比旁邊的高的答案。
那么這樣就分類轉移。
- \(f_{i,0,0} = \max(f_{i-1,1,1},f{i-1,2,1})+a_{i,0}\)
- \(f_{i,1,0} = f_{i-1,2,1}+a_{i,1}\)
- \(f_{i,1,1} = f_{i-1,0,0}+a_{i,1}\)
- \(f_{i,2,1} = \max(f_{i-1,0,0},f_{i-1,1,0})+a_{i,0}\)
這個的意義還是比較明顯的。
剩下的就是我們要考慮這個東西是一個環的情況了。
如果這個是一個環,那么我們還要考慮 \(1\) 和 \(n\) 的關系。
這個因為其實只有 \(3\) 種狀態,枚舉一下 \(1\) 選擇的樹苗,然后分別做一次 \(dp\) 就好了。
最后選擇合法的方案統計答案。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,two = 2e3+10,inf = 1e9+10;
auto max = [](auto x,auto y) {return x >y ? x : y;}; auto min = [](auto x,auto y) {return x < y ? x : y;};
#define int long long
namespace xin
{
int f[maxn][3][3];
int a[maxn][3];
int n,ans;
inline short main()
{
io >> n;
try(i,1,n)
io >> a[i][0] >> a[i][1] >> a[i][2];
try(j,0,2)
{
memset(f[1],0,sizeof(f[1]));
f[1][j][1] = f[1][j][0] = a[1][j];
try(i,2,n)
{
f[i][0][0] = max(f[i-1][1][1],f[i-1][2][1]) + a[i][0];
f[i][1][0] = f[i-1][2][1] + a[i][1];
f[i][1][1] = f[i-1][0][0] + a[i][1];
f[i][2][1] = max(f[i-1][0][0],f[i-1][1][0]) + a[i][2];
}
try(i,0,j-1) ans = max(ans,f[n][i][0]);
try(i,j+1,2) ans = max(ans,f[n][i][1]);
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
P1353 [USACO08JAN]Running S
又是一個 \(dp\)
上來狀態其實應該還是比較好想的。
\(f_{i,j}\) 即為 \(i\) 分鍾時,\(j\) 疲勞度時的答案。
那么我們考慮如何轉移
然后自然 \(f_{n,0}\) 為答案
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,two = 2e3+10,inf = 1e9+10;
auto max = [](auto x,auto y) {return x >y ? x : y;}; auto min = [](auto x,auto y) {return x < y ? x : y;};
#define int long long
namespace xin
{
int f[10001][501];
int a[maxn];
int n,m;
inline short main()
{
io >> n >> m;
try(i,1,n) io >> a[i];
// memset(f,128,sizeof(f));
// f[1][0] = 0; f[1][1] = a[1];
try(i,1,n)
{
// try(j,0,m) f[i][j] = f[i-1][j+1];
try(j,1,std::min(i,m)) f[i][0] = std::max(f[i][0],std::max(f[i-1][0],f[i-j][j]));
try(j,0,m)
{
if(j - 1 >= 0) f[i][j] = std::max(f[i][j],f[i-1][j-1] + a[i]);
// if(j + 1 <= m) f[i][j] = std::max(f[i][j],f[i-1][j+1]);
}
}
// try(i,1,n)
// {
// try(j,0,m)
// cout<<f[i][j]<<' ';
// cout<<endl;
// }
cout<<f[n][0]<<endl;
return 0;
}
}
signed main() {return xin::main();}
擴展域並查集
高級玩意,感覺像是一些思維游戲里面出的題目。
至於為啥要學這個玩意呢,似乎是因為這一類的題目似乎完全連暴力都無法打出。
所以就只能學這個東西了。
其實本來的並查集就是從 \(1\) 到 \(n\)
也就是
try(i,1,n) fa[i] = i;
但是這個擴展域會變成兩倍的東西,是因為他要分開兩個域。
一般來說同樣一個東西賦予了他兩個性質,將其本身只有一個的節點分裂成為兩個,之后直接維護節點之間的連通性從而得到某些節點之間的關系。
try(i,1,(n<<1)) fa[i] = i;
所以也就變成了這個樣子。
poj1733/acwing239 party game
這個題目要做一個轉化。
如果奇偶性是相同的,那么 \(he_{r}\) 與 \(he_{l-1}\) 的奇偶性相同。
如果不相同,則不相同。
其中 \(he\) 就代表着前綴和。
那么我們維護的東西就像是下圖。
其中 \(0\),\(3\) 維護的是其中一個節點的奇數域與偶數域。
當詢問是偶數的時,那么代表 \((l-1)_{odd}\) 與 \(r_{odd}\),\((l-1)_{even}\) 與 \(r_{even}\) 可以互相推出。
如果詢問時奇數個,那么代表 \((l-1)_{odd}\) 與 \(r_{even}\) 與 \(r_{odd}\),\((l-1)_{even}\) 可以互相推出。
那么只要每一次先檢驗一下,之后再合並就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 4e6+10,two = 2e3+10,inf = 1e9+10;
auto max = [](auto x,auto y) {return x >y ? x : y;}; auto min = [](auto x,auto y) {return x < y ? x : y;};
#define int long long
namespace xin
{
class xin_data
{
public:
int l,r,val;
}d[maxn];
int lisan[maxn],cnt = 0;
int n,m;
char s[maxn];
int fa[maxn];
inline int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
auto merge = [](int x,int y)
{
x = find(x); y = find(y);
if(x == y) return;
fa[x] = y;
};
inline short main()
{
freopen("t.txt","r",stdin);
io >> n >> m;
try(i,1,m)
{
io >> d[i].l >> d[i].r;
scanf("%s",s+1);
d[i].val = s[1] == 'o';
lisan[++cnt] = d[i].l - 1; lisan[++cnt] = d[i].r;
}
std::sort(lisan+1,lisan+cnt+1); int k = std::unique(lisan + 1,lisan + cnt + 1) - (lisan + 1);
try(i,1,m)
d[i].l = std::lower_bound(lisan+1,lisan+k+1,d[i].l-1) - lisan,d[i].r = std::lower_bound(lisan+1,lisan+k+1,d[i].r) - lisan;
// sb(d[i].l),jb(d[i].r);
// debug;
try(i,1,(m << 2)) fa[i] = i;
try(i,1,m)
{
int oddx = d[i].l,evenx = d[i].l + k,oddy = d[i].r,eveny = d[i].r + k;
if(!d[i].val)
{
if(find(oddx) == find(eveny))
{
cout<<i - 1<<endl;
return 0;
}
merge(oddx,oddy); merge(evenx,eveny);
}
else
{
if(find(oddx) == find(oddy))
{
cout<< i - 1<<endl;
return 0;
}
merge(oddx,eveny); merge(oddy,evenx);
}
}
cout<<m<<endl;
return 0;
}
}
signed main() {return xin::main();}
P4865 Samcompu Loves Water
這個題目看錯題目了。。。
還是因為題目太長了。。。
不不不,是因為題目太水了
我們到最后發現 \(k\leq1000\),所以復雜度一定和 \(k\) 有關。
我們可以將詢問離線。
那么我們再看剩下的所有邊,找到比它小的邊,然后每一個合法的邊的兩個點並查集起來,記得記錄下來 \(siz\) 的大小。
之后每次合並一次之前,我們就先 ans+=siz[fx]*siz[fy]*2
,乘二是因為這個東西的 \((x,y)\) 和 \((y,x)\) 是不同的方案。
之后將每一個合並就行了,注意離線的統計答案。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 4e6+10,two = 2e3+10,inf = 1e9+10;
auto max = [](auto x,auto y) {return x >y ? x : y;}; auto min = [](auto x,auto y) {return x < y ? x : y;};
#define int long long
namespace xin
{
class xin_data
{
public:
int tim,k,id;
}d[maxn];
class xin_edge
{
public:
int x,y,w,id;
}edge[maxn];
int t,n;
std::vector<xin_data>vec[10001];
int fa[maxn],siz[maxn];
inline int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
int ans[maxn];
inline short main()
{
io >> t >> n;
try(i,1,n-1) io >> edge[i].x >> edge[i].y >> edge[i].w,edge[i].id = i;
try(i,1,t)
{
io >> d[i].tim >> d[i].k; d[i].id = i;
vec[d[i].k].emplace_back(d[i]);
}
std::sort(edge+1,edge+n,[](const xin_edge &x,const xin_edge &y) {return x.w < y.w;});
try(i,1,n-1) if(vec[i].size())
{
std::sort(vec[i].begin(),vec[i].end(),[](const xin_data &x,const xin_data &y){return x.tim < y.tim;});
try(j,1,n) fa[j] = j,siz[j] = 1;
int zhi = 1,temp = 0;
for(auto v : vec[i])
{
try(j,zhi,n-1)
{
if(i == edge[j].id) continue;
if(edge[j].w >= v.tim) break;
zhi = j + 1;
int x = edge[j].x,y = edge[j].y;
int fx = find(x),fy = find(y);
temp += siz[fx] * siz[fy] * 2;
fa[fy] = fx;
siz[fx] += siz[fy]; siz[fy] = 0;
}
// try(j,1,n-1) if(edge[j].id == i) {ans[v.id] = siz[find(edge[i].x)] * siz[find(edge[i].y)] * 2; break;}
ans[v.id] = temp;
}
}
try(i,1,t) printf("%lld\n",ans[i]);
return 0;
}
}
signed main() {return xin::main();}
CF1594D The Number of Imposter
今天似乎做了一堆並查集的題目。
這個題目還是剛剛學的擴展域並查集
實現方法似乎比例題還簡單一些。
我們還是使用這個圖說事
這次每個點的兩個性質就是真話和假話。
之后我們維護每一個聯通塊的 \(siz\)
因為我們並不能確定哪一個是真話的,哪一個是假話的。
換句話說,就是我們可以任意選擇一種成為假話的或者是真話的。
因為題目當中要求的是最大的,所以對於每一個聯通快取 \(\max\) 就行了。
不合法的情況就是在 \(find(i) == find(i+n)\) 的時候,因為 \(i+n\) 和 \(i\) 其實是不同的性質,但是它強行搞成一個了,所以直接輸出 \(-1\)。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 4e6+10,two = 2e3+10,inf = 1e9+10;
auto max = [](auto x,auto y) {return x >y ? x : y;}; auto min = [](auto x,auto y) {return x < y ? x : y;};
#define int long long
namespace xin
{
int fa[maxn];
int n,T,m,siz[maxn];
char s[maxn];
inline int find(int x)
{
if(fa[x] == x) return fa[x];
// siz[fa[x]] += siz[x]; siz[x] = 0;
return fa[x] = find(fa[x]);
}
inline void merge(int x,int y)
{
x = find(x); y = find(y);
if(x == y) return ;
siz[x] += siz[y]; siz[y] = 0;
fa[y] = x;
}
inline short main()
{
io >> T;
while(T--)
{
io >> n >> m;
try(i,1,(n << 1)) fa[i] = i,siz[i] = (i <= n);
try(i,1,m)
{
register int x,y; io >> x >> y; scanf("%s",s+1);
// printf("%s\n",s+1);
if(s[1] == 'i')
{
merge(x,y+n); merge(x+n,y);
}
else
{
merge(x,y); merge(x+n,y+n);
}
}
int ans = 0;
try(i,1,n)
{
if(find(i) == find(i + n)) {ans = -1; break;}
ans += std::max(siz[find(i)],siz[find(i+n)]);
siz[find(i)] = siz[find(i+n)] = 0;
}
printf("%lld\n",ans);
}
return 0;
}
}
signed main() {return xin::main();}
Day -18
老實交代,其實這一天的博客咕掉了。
然而今天來補上。
集合均值
感覺自己看到期望的題目就害怕。
但是其實這個題目遠遠不如之前的題目難。
說白了,就是一個簽到的題目。
然而因為自己看到是期望的題目所以就跳過了。。。。
這個題目考察的最多最多就是一個期望的線性性,還有就是卡常
話說對於常數的要求似乎是很大的。
因為一直開着 #define int long long
所以卡了老半天。
線性求逆元行了。
話說都 1e7 了,還能怎么求
這個題目的解法就是我們發現對於每一個數的貢獻其實都是相同的,那么我們只要觀察它的概率就好了。
我們容易發現,這個數字的概率其實是一個后綴和的關系。
大概是這個樣子:
我們對於每一列分別統計,那么每一列的貢獻就是 \(\frac{i}{i+1}\)
那么問題就很好解決了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,two = 2e3+10,inf = 1e9+10;
auto max = [](auto x,auto y) {return x >y ? x : y;}; auto min = [](auto x,auto y) {return x < y ? x : y;};
// #define int long long
namespace xin
{
const int mod(998244353);
int n,m;
ll inv[maxn*20],he,ans;
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(mos);
#endif
io >> n >> m;
// he %= mod;
inv[0] = inv[1] = 1;
// for(int i=2;i<=n*m+1;++i) inv[i]=mod-mod/i*inv[mod%i]%mod;
int ms = n*m+1;
try(i,2,ms)
{
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
// ans += (i-1) * inv[i] % mod; ans -= (ans >= mod) ? mod : 0;
}
// return 0;
// return 0;
// try(i,1,ms-1) (ans += i * inv[i+1] % mod) %= mod;
ll temp = 0;
try(i,1,ms-1) (temp += inv[i+1] * i) %= mod;
temp = temp * inv[n*m] % mod;
// jb(temp);
// ans *= he * inv[n] % mod;
he = 0;
try(i,1,n)
{
register ll x; io >> x;
(he += x * m) %= mod;
}
// jb(he);
cout<<temp * he % mod<<endl;
return 0;
}
}
signed main() {return xin::main();}
聚烷撐乙二醇
其實也是一個簡單題。
然后因為概率,我又跳過了
我們從后面向前推,假設從 \(i\) ~ \(n\) 的概率是 \(f_i\)。
那么有三種情況。
- \(f_{i+1}\ge r_i\) 那么這個 \(f_i=f_{i+1}\)
- \(f_{i+1}\leq l_i\) 那么這個 \(f_i=(l_i+r_i)/2\)
- 這種情況是比較麻煩的,其實也不麻煩,就是我們統計左邊和右邊的概率乘到上面就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define debug std::cerr<<"debug"<<endl
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,two = 2e3+10,inf = 1e9+10;
auto max = [](auto x,auto y) {return x >y ? x : y;}; auto min = [](auto x,auto y) {return x < y ? x : y;};
// #define int long long
namespace xin
{
using ld = long double;
const ld eps = 1e-30;
int n;
ld f[maxn],l[maxn],r[maxn],ans;
inline short main()
{
#ifdef ONLINE_JUDGE
file(pag);
#endif
scanf("%d",&n);
bool sp = 1;
try(i,1,n)
{
scanf("%Lf%Lf",&l[i],&r[i]);
if(l[i] != r[i]) sp = 0;
ans = std::max(ans,std::max(l[i],r[i]));
}
if(sp) return printf("%.5Lf\n",ans),0;
f[n] = (l[n] + r[n]) / 2.0;
throw(i,n-1,1)
{
register ld x = f[i + 1];
// jb(x);
if(x > r[i]) f[i] = x;
else if(x < l[i]) f[i] = (r[i] + l[i]) * 0.5;
else f[i] = (x - l[i]) / (r[i] - l[i] + eps) * x + ((r[i] - x) / (r[i] - l[i] + eps)) * (r[i] + x) * 0.5;
// sb(f[i])
}
printf("%.5Lf\n",f[1]);
return 0;
}
}
signed main() {return xin::main();}
技術情報局
暴力。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
namespace GenHelper {
unsigned z1, z2, z3, z4, b;
unsigned rand_() {
b = ((z1 << 6) ^ z1) >> 13;
z1 = ((z1 & 4294967294U) << 18) ^ b;
b = ((z2 << 2) ^ z2) >> 27;
z2 = ((z2 & 4294967288U) << 2) ^ b;
b = ((z3 << 13) ^ z3) >> 21;
z3 = ((z3 & 4294967280U) << 7) ^ b;
b = ((z4 << 3) ^ z4) >> 12;
z4 = ((z4 & 4294967168U) << 13) ^ b;
return (z1 ^ z2 ^ z3 ^ z4);
}
} // namespace GenHelper
std::vector<ll> a;
void get (int n, unsigned s, int l, int r) {
using namespace GenHelper;
a.emplace_back(0);
z1 = s;
z2 = unsigned((~s) ^ 0x233333333U);
z3 = unsigned(s ^ 0x1234598766U);
z4 = (~s) + 51;
for (int i = 1; i <= n; i ++) {
int x = rand_() & 32767;
int y = rand_() & 32767;
a.push_back(l + (x * 32768 + y) % (r - l + 1));
}
// return a;
}
#define int long long
namespace xin
{
int st[maxn],top,debt[maxn],he[maxn],ret[maxn];
int n,s,l,r,mod,ans;
inline short main()
{
#ifdef ONLINE_JUDGE
file(tio);
#endif
io >> n >> s >> l >> r >> mod;
get(n,s,l,r);
// for(auto v : a) cout<<v<<' '; cout<<endl;
try(i,1,n)
{
debt[top] = debt[top] * (a[i] %= mod) % mod;
int now = a[i];
while(top and a[st[top]] <= a[i])
{
(now += debt[top] * he[top] % mod) %= mod;
(debt[top-1] *= debt[top]) %= mod; top --;
}
(ret[top + 1] = a[i] * now % mod + ret[top] * debt[top] % mod) %= mod;
st[++top] = i; debt[top] = 1; he[top] = now;
ans += ret[top]; ans %= mod;
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
肯德基
莫比烏斯。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+7; const ll llinf = 1e18+7;
#define int unsigned long long
namespace xin
{
int T;
signed mu[maxn];
signed tot,p[maxn];
bool vis[maxn];
int s[maxn];
inline void pre_work(int ms)
{
mu[1] = vis[1] = 1; s[1] = 1;
try(i,2,ms)
{
if(!vis[i]) mu[i] = -1,p[++tot] = i;
for(register int j=1;j<=tot and i * p[j] <= ms;++j)
{
register int x = i * p[j];
vis[x] = 1;
if(i % p[j] == 0) {mu[x] = 0; break;}
else mu[x] = -mu[i];
}
// jb(mu[i]);
s[i] = s[i-1] + mu[i] * i * i;
// cout<<mu[i]<<endl;
// if(i == (int)1e7) cout<<s[i]<<endl;
// if(s[i] < s[i-1]) debug;
// if(i <= 10) sb(mu[i]),sb(i),jb(s[i]);
}
}
inline int sig(int n) {return !(n & 1) ? (n / 2 * (n + 1)) : ((n + 1) / 2 * n);}
int n;
inline void work()
{
// try(i,1,10) cout<<s[i]<<endl;
int ms = std::sqrt(n); ull ans = 0;
for(int l=1,r;l<=ms;l=r+1)
{
r = std::sqrt(n / (n / l / l));
ans += (s[r] - s[l-1]) * sig(n / l / l);
// jb(s[r] - s[l-1]);
}
cout<<ans<<endl;
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(kfc);
#endif
int T; io >> T;
pre_work(1e7);
while(T--)
{
io >> n;
work();
}
return 0;
}
}
signed main() {return xin::main();}
Day -17
吸取前面場次的經驗。
\(\huge{\text{不能跳題!!!}}\)
然后開始干 \(T1\)
然后發現這個 \(T1\) 有一點小難。
然后干了 \(1h\),發現這個東西實在是有點難。
但是自己推出來了一個 \(\mathcal O(n2^{log2(t)})\) 的 \(dp\)
發現理論可以 \(40pts\),但是認為似乎這個題目會人均簽到,但是自己只寫了這一點分數,有點失落。
\(T2\) 發現是一個期望。
不能跳!!!
然后發現有很多的部分分數。
整整似乎有 \(70pts\)
然后最后得了 \(50pts\)
之后改成了 \(70pts\) 的,只不過就是打了 \(3\) 個 \(dfs\) 和 \(2\) 個\(bfs\)。
淦。
70pts
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
// #define gc() getchar()
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18;
#define int long long
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],cnt_b;
inline void add(int x,int y) {edge[++cnt_b].ver = y; edge[cnt_b].next = head[x]; head[x] = cnt_b;}
int n,m,k;
const int mod = 998244353;
int key[maxn],fa[maxn],dep[maxn],siz[maxn],hson[maxn],top[maxn];
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
}
void dfs1(int x,int f)
{
dep[x] = dep[f] + 1; siz[x] = 1; fa[x] = f;
go(i,x) if(y != f)
{
dfs1(y,x);
siz[x] += siz[y];
if(siz[y] > siz[hson[x]]) hson[x] = y;
}
}
void dfs2(int x,int t)
{
top[x] = t;
if(hson[x]) dfs2(hson[x],t);
go(i,x)
{
if(y == fa[x] or y == hson[x]) continue;
dfs2(y,y);
}
}
inline int lca(int x,int y)
{
while(top[x] xor top[y])
{
if(dep[top[x]] < dep[top[y]]) std::swap(x,y);
x = fa[top[x]];
}
return dep[x] > dep[y] ? y : x;
}
inline int dis(int x,int y) {return dep[x] + dep[y] - 2 * dep[lca(x,y)];}
int a[maxn],zhi,temp[maxn];
int ans = 0,cnt = 0;
void dfs()
{
if(zhi == k)
{
try(i,1,zhi) temp[i] = a[i];
std::sort(temp+1,temp+zhi+1);
// try(i,1,zhi) cout<<key[temp[i]]<<' '; cout<<endl;
int ret = inf;
do
{
int he = 0;
try(i,1,zhi-1) he += dis(key[temp[i]],key[temp[i+1]]);
// jb(he);
// if(he == 7) {try(i,1,zhi) cout<<key[temp[i]]<<' '; cout<<endl;}
ret = std::min(ret,he);
} while (std::next_permutation(temp+1,temp+zhi+1));
// sb(key[temp[1]]); sb(key[temp[2]]); jb(ret);
(ans += ret) %= mod;
// debug;
++cnt;
return ;
}
try(i,a[zhi]+1,m)
{
a[++zhi] = i;
dfs();
zhi --;
}
}
int ton[maxn];
bool vis[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(tree);
#endif
io >> n >> m >> k;
try(i,1,m) io >> key[i];
try(i,1,n-1)
{
register int x,y; io >> x >> y;
add(x,y); add(y,x);
}
dfs1(1,0); dfs2(1,1);
if(k == 2)
{
try(i,1,m) try(j,i+1,m)
{
++cnt;
(ans += dis(key[i],key[j])) %= mod;
}
// jb(ans); jb(cnt);
cout<<ans * ksm(cnt,mod-2) % mod<<endl;
return 0;
}
else if(k == m and n >= 10)
{
// debug;
int allca = key[1];
try(i,2,m) allca = lca(allca,key[i]);
memset(head,0,sizeof(int) * (n + 1)); cnt_b = 0;
try(i,1,m)
{
int x = key[i];
// jb(x);
// debug;
while(!vis[x] and x != allca)
{
vis[x] = 1;
add(fa[x],x); add(x,fa[x]);
ans ++;
// sb(fa[x]); jb(x);
x = fa[x];
}
}
// jb(ans);
int far1;
memset(vis,0,sizeof(bool) * (n + 1));
std::queue<std::pair<int,int>>q; vis[key[1]] = 1; q.push(std::make_pair(key[1],0));
while(q.size())
{
register int x = q.front().first; q.pop();
far1 = x;
go(i,x) if(!vis[y])
{
vis[y] = 1; q.push(std::make_pair(y,0));
}
}
std::pair<int,int>far2;
memset(vis,0,sizeof(bool) * (n + 1));
q.push(std::make_pair(far1,0)); vis[far1] =1;
while(q.size())
{
std::pair<int,int> x = q.front(); q.pop();
far2 = x;
go(i,x.first) if(!vis[y])
{
vis[y] = 1; q.push(std::make_pair(y,x.second+1));
}
}
cout<<ans * 2 - far2.second<<endl;
// sb(far2.first); jb(far2.second);
return 0;
}
else
{
// debug;
dfs();
// jb(ans); jb(cnt);
cout<<ans * ksm(cnt,mod-2) % mod<<endl;
return 0;
}
return 0;
}
}
signed main() {return xin::main();}
按位或
似乎不是很簡單。
這個是一個容斥。
就是關於一個只有 \(0,1,2\) 剩余系的容斥。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
// #define gc() getchar()
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18;
#define int long long
namespace xin
{
const int mod = 998244353;
int n,t;
int c[1001][1001];
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(or);
#endif
io >> n >> t;
try(i,0,1000)
{
c[i][0] = 1;
try(j,1,i)
(c[i][j] = c[i-1][j] + c[i-1][j-1]) %= mod;
}
// jb(c[3][1]);
// jb(c[2][1]); jb(c[2][0]);
int ans = 0;
int num1 = 0,num2 = 0;
throw(i,62,0)
{
if((t >> i) & 1) num1 ++;
i --;
}
throw(i,63,0)
{
if((t >> i) & 1) num2 ++;
i --;
}
// sb(num1); jb(num2);
// jb(c[3][2]);
try(x,0,num1) try(y,0,num2)
{
int temp = 0,base = (num1 + num2 - x - y) & 1 ? -1 : 1;
// cout<<base<<endl;
try(i,0,x) try(j,0,y) if(!((i - j) % 3))
(temp += c[x][i] * c[y][j] % mod) %= mod;
// jb(temp);
(ans += ksm(temp,n) * c[num1][x] % mod * c[num2][y] % mod * base % mod + mod) %= mod; ans = (ans + mod) % mod;
// jb(ans);
base = -base;
}
cout<<ans % mod<<endl;
return 0;
}
}
signed main() {return xin::main();}
最短路徑
我們先轉化一下題意,然后發現這個其實就是求虛樹上邊長的期望的二倍減去虛樹上面最長鏈的期望
那么我們考慮每一個邊的貢獻。
之后再 \(m^3\) 枚舉最長鏈就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
// #define gc() getchar()
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18;
#define int long long
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],cnt_b;
inline void add(int x,int y) {edge[++cnt_b].ver = y; edge[cnt_b].next = head[x]; head[x] = cnt_b;}
int n,m,k;
const int mod = 998244353;
int key[maxn],fa[maxn],dep[maxn],siz[maxn],hson[maxn],top[maxn];
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
}
void dfs1(int x,int f)
{
dep[x] = dep[f] + 1; siz[x] = 1; fa[x] = f;
go(i,x) if(y != f)
{
dfs1(y,x);
siz[x] += siz[y];
if(siz[y] > siz[hson[x]]) hson[x] = y;
}
}
void dfs2(int x,int t)
{
top[x] = t;
if(hson[x]) dfs2(hson[x],t);
go(i,x)
{
if(y == fa[x] or y == hson[x]) continue;
dfs2(y,y);
}
}
inline int lca(int x,int y)
{
while(top[x] xor top[y])
{
if(dep[top[x]] < dep[top[y]]) std::swap(x,y);
x = fa[top[x]];
}
return dep[x] > dep[y] ? y : x;
}
int fac[maxn],inv[maxn];
inline int c(int n,int m) {if(m > n) return 0; return fac[n] * inv[m] % mod * inv[n-m] % mod;}
// inline int dis(int x,int y) {return dep[x] + dep[y] - 2 * dep[lca(x,y)];}
int big[maxn];
bool imp[maxn];
int ans = 0;
void dfs3(int x,int f)
{
big[x] = imp[x];
go(i,x) if(y != f)
{
dfs3(y,x);
big[x] += big[y];
}
(ans += 2ll * (c(m,k) - c(big[x],k) - c(m - big[x],k) + 4ll * mod)) %= mod;
}
int d[maxn];
void dfs(int x,int f)
{
d[x] = d[f] + 1;
go(i,x) if(y != f)
dfs(y,x);
}
int dis[301][301];
inline short main()
{
#ifdef ONLINE_JUDGE
file(tree);
#endif
io >> n >> m >> k;
fac[0] = inv[0] = 1;
try(i,1,m) fac[i] = fac[i-1] * i % mod;
inv[m] = ksm(fac[m],mod-2);
throw(i,m-1,1) inv[i] = inv[i+1] * (i + 1) % mod;
// jb(c(3,1));
try(i,1,m) io >> key[i],imp[key[i]] = 1;
try(i,1,n-1)
{
register int x,y; io >> x >> y;
add(x,y); add(y,x);
}
dfs1(1,0); dfs2(1,1);
try(i,1,m)
{
dfs(key[i],0);
try(j,1,m)
dis[i][j] = d[key[j]] - d[key[i]];//,cout<<dis[i][j]<<endl;
}
dfs3(1,0);
// jb(ans);
try(i,1,m)
{
try(j,i+1,m)
{
int sum=0;
try(l,1,m)
{
if(l==i or l==j)continue;
if(dis[l][i]<dis[i][j] and dis[l][j]<dis[i][j])sum++;
else if(l>i and dis[l][i]<dis[i][j] and dis[l][j]<=dis[i][j])sum++;
else if(l>j and dis[l][i]<=dis[i][j] and dis[l][j]<=dis[i][j])sum++;
}
ans=(ans-c(sum,k-2)*dis[i][j] % mod + mod) % mod;
}
}
cout<<ans * ksm(c(m,k),mod-2) % mod<<endl;
return 0;
}
}
signed main() {return xin::main();}
仙人掌 and 對弈
咕
Day -16
[CSP-S2019] Emiya 家今天的飯 | P5664
話說昨天似乎還留下一個[CSP-S2019] Emiya 家今天的飯 | P5664
然后寫了一個垃圾爆搜,獲得了 \(32pts\) 高分。。。
32pts
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
#define int long long
namespace xin
{
const int mod = 998244353;
int mat[101][2001];
int n,m;
int a[maxn],zhi = 0;
int ans = 0;
int b[maxn],cnt = 0;
int num[maxn];
void dfs2(int ms)
{
if(cnt == ms)
{
int he = 1;
memset(num,0,sizeof(int) * (m + 1));
// try(i,1,cnt) cout<<b[i]<<' ';
// cout<<endl;
try(i,1,cnt) num[b[i]] ++;
try(i,1,m) if(num[i] > (ms >> 1)) return ;
try(i,1,cnt)
(he *= mat[a[i]][b[i]]) %= mod;
(ans += he) %= mod;
return;
}
try(i,1,m)
{
b[++cnt] = i;
dfs2(ms);
cnt --;
}
}
void dfs(int ms)
{
if(zhi == ms)
{
// try(i,1,zhi) cout<<a[i]<<' ';
// cout<<endl;
dfs2(ms);
return ;
}
try(i,a[zhi]+1,n)
{
a[++zhi] = i;
dfs(ms);
zhi --;
}
}
inline short main()
{
io >> n >> m;
try(i,1,n) try(j,1,m) io >> mat[i][j];
try(i,2,n) dfs(i);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
之后我們有一個 \(dp\) 的思路,這個可以引導向正解,並且似乎可以得到很多的分數。
我們最最煩的一個限制其實就是那個 \(\frac{k}{2}\) 的那個限制。
我們正難則反一下,那么我們就是說我們其實可以用全部的方案數減去所有不合法的方案數。
那么其實這樣也就好辦多了。
我們首先考慮全部的方案數,也就是所有合法的和不合法的方案數。
我們設 \(g_{i,j}\) 為前 \(i\) 行,選擇了 \(j\) 個的方案數。
那么我們就可以知道總的方案數就是 \(\sum_{i=0}^ng_{n,i}\)
那么這個東西如何轉移。
我們記錄矩陣的每一行的總和為 \(he_i\)
那么 \(g_{i,j} = g_{i-1,j} + he_i * g_{i-1,j-1}\)
這個東西實際上就表示 上一行選j個的方案數加上上一行選j-1的方案數再乘上這一行的總和
,因為這一行的每一個數都可以選,所以乘上總和。
之后考慮不合法的情況。
我們設 \(f_{i,j,k}\) 為 \(col\) 這一列,前 \(i\) 行,在這一列里面選擇了 \(j\) 個,然后在其他列選擇了 \(k\) 個的方案數。
那么轉移也就是顯然:\(f_{i,j,k} = f_{i-1,j-1,k} * a_{i,col} + f_{i-1,j,k-1} * (he_i - a_{i,col})\)
之后做差就是 \(84pts\) 代碼。
84pts
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
#define int long long
namespace xin
{
const int mod = 998244353;
int mat[101][2001];
int n,m;
int he[maxn];
int g[201][401];
int f[41][41][41];
inline short main()
{
io >> n >> m;
try(i,1,n) try(j,1,m) io >> mat[i][j],he[i] += mat[i][j],he[i] %= mod;
g[0][0] = 1;
try(i,1,n) try(j,0,i)
(g[i][j] = g[i-1][j] + (j > 0 ? g[i-1][j-1] * he[i] % mod : 0)) %= mod;
int ans = 0;
try(i,1,n) (ans += g[n][i]) %= mod;
// jb(ans);
try(col,1,m)
{
memset(f,0,sizeof(f));
f[0][0][0] = 1;
try(i,1,n) try(j,0,n) try(k,0,n)
f[i][j][k] = (f[i-1][j][k] + (j > 0 ? f[i-1][j-1][k] * mat[i][col] % mod : 0) + (k > 0 ? f[i-1][j][k-1] * (he[i] - mat[i][col])% mod : 0)) % mod;
try(j,0,n) try(k,0,j-1)
ans = (ans - f[n][j][k] + mod) % mod;
}
// cout<<ans<<endl;
// try(col,1,m)
// {
// memset(f,0,sizeof(f));
// f[0][n] = 1;
// try(i,1,n) try(j,n-i,n+i)
// f[i][j] = (f[i-1][j] + mat[i][col] * f[i-1][j-1] % mod + (he[i] - mat[i][col]) * f[i-1][j+1] % mod) % mod;
// try(i,1,n)
// ans = (ans - f[n][n+i] + mod) % mod;
// }
cout<<ans<<endl;
// cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
之后我們考慮正解的做法。
這個就是我們其實並不關心的是 \(j\) 和 \(k\) 的具體的數值,但是我們關心他們的大小關系。
所以我們把第二維改成 \(f_{i,j}\) 表示 \(col\) 這一列比其他列多了 \(j\) 個。
那么轉移類似。
這樣就得到了正確的復雜度做法。
100pts
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
#define int long long
namespace xin
{
const int mod = 998244353;
int mat[101][2001];
int n,m;
int he[maxn];
int g[201][401];
int f[201][401];
inline short main()
{
io >> n >> m;
try(i,1,n) try(j,1,m) io >> mat[i][j],he[i] += mat[i][j],he[i] %= mod;
g[0][0] = 1;
try(i,1,n) try(j,0,i)
(g[i][j] = g[i-1][j] + (j > 0 ? g[i-1][j-1] * he[i] % mod : 0)) %= mod;
int ans = 0;
try(i,1,n) (ans += g[n][i]) %= mod;
// jb(ans);
// try(col,1,m)
// {
// memset(f,0,sizeof(f));
// f[0][0][0] = 1;
// try(i,1,n) try(j,0,n) try(k,0,n)
// f[i][j][k] = (f[i-1][j][k] + (j > 0 ? f[i-1][j-1][k] * mat[i][col] % mod : 0) + (k > 0 ? f[i-1][j][k-1] * (he[i] - mat[i][col])% mod : 0)) % mod;
// try(j,0,n) try(k,0,j-1)
// ans = (ans - f[n][j][k] + mod) % mod;
// }
// cout<<ans<<endl;
try(col,1,m)
{
memset(f,0,sizeof(f));
f[0][n] = 1;
try(i,1,n) try(j,n-i,n+i)
f[i][j] = (f[i-1][j] + mat[i][col] * f[i-1][j-1] % mod + (he[i] - mat[i][col]) * f[i-1][j+1] % mod) % mod;
try(i,1,n)
ans = (ans - f[n][n+i] + mod) % mod;
}
cout<<ans<<endl;
// cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
codeforces 101350 G
一道比較板子的容斥題目。
發現 \(k\) 比較小。
那么就考慮直接枚舉 \(k\) 的狀態。
我們還是將答案表示為 總共的答案-不合法的答案
那么我們首先就是計算矩陣當中子矩陣的總數量。
發現其實就是拿兩條線去卡出矩形就好了。
那么總共的方案數其實就是 \(\dbinom{2}{n+1}*\dbinom{2}{m+1}\)
之后考慮不合法的情況。
我們如果硬算似乎很難算出來,但是我們可以算出來包含 \(i\) 個點的方案數。
那么我們總共的不合法的數量其實就是
\(f_i\) 就代表包含 \(i\) 個點的方案數。
之后用 \(ans\) 減去就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10;
#define int long long
auto max = [](auto x,auto y) {return x > y ? x : y;}; auto min = [](auto x,auto y) {return x < y ? x : y;};
namespace xin
{
int n,m,k;
int ans = 0;
class xin_data
{
public:
int x,y;
xin_data(){}
xin_data(int x,int y):x(x),y(y){}
}d[maxn];
inline short main()
{
int T; io >> T;
while(T--)
{
io >> n >> m >> k;
ans = ((n + 1) * n / 2) * ((m + 1) * m / 2);
try(i,1,k) io >> d[i].x >> d[i].y;
// cout<<ans<<endl;
int ms = (1 << k) - 1;
int ret = 0;
try(s,1,ms)
{
int cnt = 0;
int temp = s;
while(temp) cnt += (temp & 1),temp >>= 1;
int rx = 0,lx = inf,ry = 0,ly = inf;
try(i,1,k) if((s >> (i - 1)) & 1)
{
rx = max(rx,d[i].x); ry = max(ry,d[i].y);
lx = min(lx,d[i].x); ly = min(ly,d[i].y);
}
// int he = (n - (rx - lx)) * (m - (ry - ly));
int he = lx * ly * (n - rx + 1) * (m - ry + 1);
// sb(lx); sb(rx); sb(ly); jb(ry);
if(cnt & 1) ret += he;
else ret -= he;
}
printf("%lld\n",ans - ret);
}
return 0;
}
}
signed main() {return xin::main();}

[USACO06NOV]Corn Fields G | P1879
這個做法的理論復雜度可能不是很對。
但是不知道為什么我跑得飛快。
\(10\) 個點一共只用了 \(33ms\)
很普通的,我們記錄 \(f_{i,s}\) 為 \(i\) 行,當前狀態為 \(s\) 的方案數。
那么我們的目標就是 \(\sum f_{n,s}\)
我們考慮這個東西如何轉移。
首先就是考慮什么樣子的 \(s\) 是合法的。
farmer john
要求我們每一個草地都不能相連,那么我們的 \(s\) 中的每一個有 \(1\) 的二進制位也不能相連。
這個 \(\mathcal O(12)\) 進行一個判斷就好了。
然后我們還要求相鄰兩行的草地也不能有一點相鄰。
那么我們分別枚舉兩行的狀態,之后取 &
要求其為 \(0\) 就好了。
總的復雜度應該是 \(\mathcal O(12n2^{2m})\),\(n,m\leq 12\) 似乎不是很對,但是跑得飛快。
注意!!!
&
符號比 ==
的運算優先級還低!!!!!導致我剛開始WA成50了
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10;
#define int long long
auto max = [](auto x,auto y) {return x > y ? x : y;}; auto min = [](auto x,auto y) {return x < y ? x : y;};
namespace xin
{
const int mod = 100000000;
int f[20][(1 << 13) + 1];
int n,m;
int a[maxn];
inline bool pan(int x)
{
try(i,0,11) if(((x >> i) & 1) and ((x >> i) & 1) == ((x >> i + 1) & 1)) return false;
return true;
}
inline short main()
{
io >> n >> m;
try(i,1,n)
{
try(j,1,m)
{
register int x; io >> x;
if(x) a[i] |= (1 << j - 1);
}
// sb(i); jb(a[i]);
}
f[0][0] = 1;
int ms = (1 << m) - 1;
// try(i,1,ms) if(pan(i)) f[0][i] = 1;
// jb(ms);
// jb(pan(5));
// cout<<(5 & 7)<<endl;
// jb(pan(5));
try(i,1,n)
{
// sb(i); jb(a[i]);
try(s,0,ms) if((s & a[i]) == s and pan(s))
{
// cout<<s<<endl;
try(st,0,ms) if((st & s) == 0 and pan(st))
(f[i][s] += f[i-1][st]) %= mod;
}
}
int ans = 0;
try(s,0,ms) (ans += f[n][s]) %= mod;
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
[NOIP2014 提高組] 尋找道路 | P2296
話說我犯了一年的錯誤的,今天才查出來啊。
思路這個題目還是非常簡單的。
首先我們要找到合法的點,那么反向 \(bfs\) 一遍其實就好了。
之后正向再來一個 \(bfs\) 就能找到最短的了。
但是自己不知道為什么一直 \(40pts\).
最后一直狂調,發現自己的廣搜如果手寫的隊列,一直模擬的其實都是棧,而不是隊列。
這樣最短的距離就會找錯了。。
一道歷史遺留問題解決了
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
// #define int long long
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],cnt;
auto add = [](int x,int y) {edge[++cnt].ver = y; edge[cnt].next = head[x]; head[x] = cnt;};
std::pair<int,int>temp[maxn];
int n,m,st,ed,q[maxn],zhi,tim[maxn];
bool vis[maxn];
bool nb[maxn];
int dis[maxn];
std::vector<int>vec[maxn/10];
inline short main()
{
io >> n >> m;
try(i,1,m)
{
register int x,y; io >> x >> y;
add(y,x); vec[x].emplace_back(y);
// temp[i] = std::make_pair(x,y);
}
io >> st >> ed;
// debug;
q[zhi = 1] = ed; vis[ed] = 1;
// debug;
while(zhi)
{
int x = q[zhi--];
go(i,x) if(!vis[y])
{
vis[y] = 1;
q[++zhi] = y;
}
}
if(!vis[st]) {puts("-1"); exit(0);}
memset(head,0,sizeof(int) * (n + 1)); cnt = 0;
// memset(head,0,sizeof(head)); memset(edge,0,sizeof(edge));
// try(i,1,m) add(temp[i].first,temp[i].second);
try(i,1,n)
{
nb[i] = 1;
if(!vis[i]) nb[i] = 0;
if(nb[i]) for(auto y : vec[i]) if(!vis[y])
{
nb[i] = 0; break;
}
}
// try(i,1,n) if(!nb[i]) cout<<"i = "<<i<<endl;
// jb(nb[4575]);
// try(i,1,n) cout<<vis[i]<<endl;
int front = 0,back = 1; dis[st] = 0;
q[++front] = st;
// debug;
while(front >= back)
{
int x = q[back++];
if(!nb[x]) continue;
// sb(zhi); jb(x);
// sb(t); jb(x);
if(x == ed) {printf("%d\n",dis[x]); exit(0);}
for(auto y : vec[x]) if(!dis[y])
{
// jb(y);
dis[y] = dis[x] + 1;
q[++front] = y;
}
}
cout<<-1<<endl;
return 0;
}
}
signed main() {return xin::main();}
[NOIP2010 提高組] 烏龜棋 | P1541
這是一個不是正解的方法。
因為需要卡億卡常。
我們首先看到 \(50pts\) 做法,發現可以直接5維dp數組
設 \(f_{i,num1,num2,num3,num4}\) 為走到 \(i\) 之后還有 \(num1\) 個 \(1\) 卡片.....
然后容易得到轉移:
if(num1 < num[1] and i - 1 >= 1)
f[i][num1][num2][num3][num4] = std::max(f[i][num1][num2][num3][num4],f[i-1][num1+1][num2][num3][num4] + scr[i]);
if(num2 < num[2] and i - 2 >= 1)
f[i][num1][num2][num3][num4] = std::max(f[i][num1][num2][num3][num4],f[i-2][num1][num2+1][num3][num4] + scr[i]);
if(num3 < num[3] and i - 3 >= 1)
f[i][num1][num2][num3][num4] = std::max(f[i][num1][num2][num3][num4],f[i-3][num1][num2][num3+1][num4] + scr[i]);
if(num4 < num[4] and i - 4 >= 1)
f[i][num1][num2][num3][num4] = std::max(f[i][num1][num2][num3][num4],f[i-4][num1][num2][num3][num4+1] + scr[i]);
對於 \(100\%\) 的數據來說,這個 \(5\) 維的 \(dp\) 是完全卡不下的。
因為需要 \(3000MIB\) 的內存。
但是我們發現這個東西的第一維似乎只需要 \(4\) 個狀態。
那么我們就可以開始滾了。
APJifengc:你可以滾了
然后我們如果使用 \(\%4\) 處理。
那么。。。
我們發現其實 \(4\) 是 \(2^2\),那么在取模的時候就可以直接對這個數字進行按位與 \(mod-1\)。
然后發現還是比較慢。
然后再經過大力卡常,之后就能過去了。
回頭看了看題解,發現全都是四維的dp
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
auto max = [](int x,int y) {return x > y ? x : y;};
// #define int long long
namespace xin
{
int f[4][41][41][41][41];
int num[5];
int n,m;
int a[maxn],b[maxn];
int scr[maxn];
const int mod = 4;
inline short main()
{
io >> n >> m;
try(i,1,n) io >> scr[i];
try(i,1,m)
{
register int x; io >> x;
num[x] ++;
}
f[1][num[1]][num[2]][num[3]][num[4]] = scr[1];
try(i,2,n)
{
try(num1,0,num[1]) try(num2,0,num[2])
try(num3,0,num[3]) try(num4,0,num[4])
{
if(num1 xor num[1] and i - 1 >= 1)
f[i&(mod-1)][num1][num2][num3][num4] = max(f[i&(mod-1)][num1][num2][num3][num4],f[(i-1+mod)&(mod-1)][num1+1][num2][num3][num4] + scr[i]);
if(num2 xor num[2] and i - 2 >= 1)
f[i&(mod-1)][num1][num2][num3][num4] = max(f[i&(mod-1)][num1][num2][num3][num4],f[(i-2+mod)&(mod-1)][num1][num2+1][num3][num4] + scr[i]);
if(num3 xor num[3] and i - 3 >= 1)
f[i&(mod-1)][num1][num2][num3][num4] = max(f[i&(mod-1)][num1][num2][num3][num4],f[(i-3+mod)&(mod-1)][num1][num2][num3+1][num4] + scr[i]);
if(num4 xor num[4] and i - 4 >= 1)
f[i&(mod-1)][num1][num2][num3][num4] = max(f[i&(mod-1)][num1][num2][num3][num4],f[(i-4+mod)&(mod-1)][num1][num2][num3][num4+1] + scr[i]);
}
}
int ans = 0;
try(num1,0,num[1]) try(num2,0,num[2]) try(num3,0,num[3]) try(num4,0,num[4])
ans = max(ans,f[n&(mod-1)][num1][num2][num3][num4]);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
獲得最最最差解,人均 100ms,我直接 3s
Day -15
比賽日。
然后多測沒有清空
今天的 \(T1\) 還是比較友好的,只不過還是想了半個小時
之后的 \(T2\) 構造失敗,多測。。。。
\(T3\) 只寫了一個暴力,其實掃描線就很好。
\(T4\) 注意拓撲 \(ban\) 邊的時候要先判斷 if(!--ind[y])q.push(y)
。
所以這個破題連爆搜都沒有打對。。。
謎之階乘
我們發現階乘連乘起來最多 \(20\) 就爆炸了。
然后因為這個的答案的區間一定是一段連續的。
所以我們直接對於 \({x}^\frac{1}{len}\)
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
#define int long long
namespace xin
{
int n;
class xin_data
{
public:
int x,y;
xin_data(){}
xin_data(int x,int y):x(x),y(y){}
}d[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(factorial);
#endif
// try(i,1,23) cout<<"i = "<<i<<" ans = "<<ans<<endl,ans *= i;
int T; io >> T;
while(T--)
{
io >> n; int zhi = 0;
if(n == 1) {printf("-1\n");continue;}
d[++zhi] = xin_data(n,n-1);
try(len,2,21)
{
int num = std::pow(n,1.0 / (double)len);
int st = std::max(1ll,num - len);
try(l,st,num)
{
int r = l + len - 1;
__int128 pi = 1;
try(i,l,r) pi *= i;
if(pi == n and l - 1) d[++zhi] = xin_data(r,l-1);
}
}
printf("%lld\n",zhi);
std::sort(d+1,d+zhi+1,[](const xin_data &x,const xin_data &y){return x.x < y.x;});
try(i,1,zhi) printf("%lld %lld\n",d[i].x,d[i].y);
}
return 0;
}
}
signed main() {return xin::main();}
子集
我們其實只用構造完前三行就好了。
所以考慮前三行的構造方案。
我們還是按照順序填第一列,之后錯一點填第二列,第三列就按照前面排序后的填。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
#define int long long
namespace xin
{
int n,k;
std::vector<int>ans[maxn];
class xin_data
{
public:
int x,id;
}d[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(subset);
#endif
int T; io >> T;
while(T--)
{
io >> n >> k;
if(n == 1 and k == 1) {printf("Yes\n1\n"); continue;}
if(n == k)
{
printf("No\n");
continue;
}
if(!((n / k) & 1))
{
int l = 1,r = n;
puts("Yes");
try(i,1,k)
{
try(j,l,l+(n/k/2)-1)
printf("%lld ",j);
try(j,r-(n/k/2)+1,r)
printf("%lld ",j);
printf("\n");
l = l + (n / k / 2);
r = r - (n / k / 2);
}
}
else
{
int zhi = 0;
int num = (1 + n) * n / 2 / k;
if(((1 + n) * n / 2) % k != 0) {puts("No"); continue;}
try(i,1,k) ans[i].clear();
try(i,1,k) ans[i].emplace_back(++zhi);
try(i,k/2+2,k) ans[i].emplace_back(++zhi);
try(i,1,k/2+1) ans[i].emplace_back(++zhi);
try(i,1,k) d[i].x = ans[i][0] + ans[i][1],d[i].id = i;
std::sort(d+1,d+k+1,[](const xin_data &x,const xin_data &y){return x.x > y.x;});
try(i,1,k) ans[d[i].id].emplace_back(++zhi);
while(1)
{
if(zhi >= n) break;
try(i,1,k) ans[i].emplace_back(++zhi);
if(zhi >= n) break;
throw(i,k,1) ans[i].emplace_back(++zhi);
}
printf("Yes\n");
try(i,1,k)
{
for(auto v : ans[i])
printf("%lld ",v);
printf("\n");
}
}
}
return 0;
}
}
signed main() {return xin::main();}
混凝土粉末
我們把每一個詢問還有修改操作放到 \(1\) ~ \(n\) 的數軸上面。
之后我們用一個掃描線對於每一個操作進行修改。
之后如果有詢問我們就在線段樹上面二分就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
#define int long long
namespace xin
{
int n,qnum;
class xin_data
{
public:
int tim,h;
int type;
xin_data(){}
xin_data(int tim,int h,int type):tim(tim),h(h),type(type){}
};
std::vector<xin_data>vec[maxn],qsum[maxn];
class xin_seg
{
private:
#define ls(fa) (fa << 1)
#define rs(fa) (fa << 1 | 1)
public:
class xin_tree{public:int s;}t[maxn<<2];
int mx,res;
void upd(int fa,int l,int r,int pos,int val)
{
if(l == r) return t[fa].s += val,void();
register int mid = l + r >> 1;
if(pos <= mid) upd(ls(fa),l,mid,pos,val);
else upd(rs(fa),mid+1,r,pos,val);
t[fa].s = t[ls(fa)].s + t[rs(fa)].s;
}
void query(int fa,int l,int r,int qr)
{
if(~res or l>qr)return ;
if(r <= qr)
{
if(l == r)
{
if(t[fa].s >= mx) res = l;
else mx -= t[fa].s;
return ;
}
register int mid = l + r >> 1;
if(t[ls(fa)].s < mx) mx -= t[ls(fa)].s,query(rs(fa),mid+1,r,qr);
else query(ls(fa),l,mid,qr);
return ;
}
int mid=l+r>>1;
query(ls(fa),l,mid,qr); query(rs(fa),mid+1,r,qr);
}
}t;
int ans[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(concrete);
#endif
// freopen("t.txt","r",stdin);
io >> n >> qnum;
try(i,1,qnum)
{
register int op; io >> op;
if(op == 1)
{
register int l,r,h; io >> l >> r >> h;
// sb(l); jb(r);
vec[l].emplace_back(xin_data(i,h,1));
vec[r+1].emplace_back(xin_data(i,h,2));
}
else
{
register int x,y; io >> x >> y;
// sb(x); jb(y);
qsum[x].emplace_back(xin_data(i,y,0));
}
}
// debug;
try(i,1,n)
{
for(auto v : vec[i])
{
if(v.type == 1) t.upd(1,1,qnum,v.tim,v.h);
else t.upd(1,1,qnum,v.tim,-v.h);
}
for(auto v : qsum[i])
{
t.res = -1; t.mx = v.h;
t.query(1,1,qnum,v.tim);
ans[v.tim] = t.res;
}
}
try(i,1,qnum) if(ans[i])
{
if(ans[i] == -1) printf("0\n");
else printf("%lld\n",ans[i]);
}
return 0;
}
}
signed main() {return xin::main();}
附上線段樹二分模板
線段樹二分
void query(int fa,int l,int r,int qr)
{
if(~res or l>qr)return ;
if(r <= qr)
{
if(l == r)
{
if(t[fa].s >= mx) res = l;
else mx -= t[fa].s;
return ;
}
register int mid = l + r >> 1;
if(t[ls(fa)].s < mx) mx -= t[ls(fa)].s,query(rs(fa),mid+1,r,qr);
else query(ls(fa),l,mid,qr);
return ;
}
int mid=l+r>>1;
query(ls(fa),l,mid,qr); query(rs(fa),mid+1,r,qr);
}
排水系統
顯然我們不能暴力將所有答案都算一遍,因此我們考慮整體統計。我們能觀察到,若 \(x\) 點的排水管道堵塞,從 \(x\) 點經過的污水噸數必然不變。因此,我們可以借此考慮 \((x, y)\) 堵塞的影響:我們可以將管道堵塞視為 \(y\) 的經過污水噸數憑空減少一個定值,而 \(x\) 其他出點的污水噸數憑空增加一個定值。
而這個憑空增加、減少可以 \(x\) 噸的污水又可以視為初始這個點上有 \(x\) 或 \(−x\) 噸污水。因此,我們可以將題目轉化回原始的情況,即沒有邊被堵塞時的情況。我們對此暴力統計,即可通過大部分特殊性質數據。而我們又發現,\(x\) 出點增加的定值可以視為加在 \(x\) 上並在 \(y\) 上減去,因此可以只修改 \(x, y\) 兩個點上的信息。復雜度 \(\mathcal O(n+k)\)。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define int long long
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10;
namespace xin
{
const int mod = 998244353;
class xin_data
{
public:
int x,w;
xin_data(){}
xin_data(int x,int w):x(x),w(w){}
};
std::vector<xin_data>vec[maxn];
int n,m,r,k;
inline int ksm(int x,int y,int ret = 1)
{
x %= mod;
while(y)
{
if(y & 1) ret = ret * x % mod ;
x = x * x %mod ; y >>= 1;
}
return ret;
}
int ind[maxn],f[maxn];
int temp[maxn];
int ans[maxn];
inline short main()
{
file(water);
io >> n >> m >> r >> k;
int he = 0;
try(i,1,k)
{
register int x,y,z; io >> x >> y >> z; z %= mod;
vec[x].emplace_back(xin_data(y,z)); ind[y] ++;
he += z;
}
int inv = ksm(he,mod-2);
std::queue<int>q;
try(i,1,m) q.push(i),f[i] = 1;
memcpy(temp,ind,sizeof(int) * (n + 1));
while(q.size())
{
register int x = q.front(); q.pop();
int inv1 = ksm(vec[x].size(),mod-2),inv2 = ksm(vec[x].size()-1,mod-2);
// cout<<x<<endl;
// cout<<vec[x].size()<<endl;
for(auto v : vec[x])
{
register int y = v.x,val = v.w; --ind[y];
// cout<<val<<endl;
// cout<<y<<inv1<<inv2<<endl;
ans[x]=(ans[x]+(f[x]*((inv2-inv1+mod)%mod)%mod)*val%mod*inv%mod*vec[x].size()%mod)%mod;
ans[y]=(ans[y]-f[x]*inv1%mod*val%mod*inv%mod-(f[x]*((inv2-inv1+mod)%mod)%mod)*val%mod*inv%mod+mod*2ll)%mod;
f[y]=(f[y]+f[x]*inv1%mod)%mod;
// cout<<f[y]<<endl;
// cout<<ans[x]<<endl;
if(!ind[y]) q.push(y);
}
}
// try(i,1,n) cout<<ans[i]<<endl;
memcpy(ind,temp,sizeof(int) * (n + 1));
try(i,1,m) ans[i] ++,q.push(i),f[i] = 1;
while(q.size())
{
register int x = q.front(); q.pop();
int inv1 = ksm(vec[x].size(),mod-2);
for(auto v : vec[x])
{
register int y = v.x,val = v.w; --ind[y];
if(!ind[y]) q.push(y);
ans[y] = (ans[y] + ans[x] * inv1 % mod) % mod;
}
}
try(i,n-r+1,n) printf("%lld ",ans[i]);
putchar('\n');
return 0;
}
}
signed main() {return xin::main();}
Day -14
考的很爆炸。
\(dp\) 方程 \(naive\) 了,發現怎么也不對。
之后交了一個暴力就走人了。
這次又忘了 \(dp\) 寫不出就加維這個原則了。
然后在 \(T1\) 上面搞了好長時間,結果后面的題目也草草寫了暴力,也沒有亂搞什么的。
其實 \(T3\) 亂搞的做法也是很快的啊。
總結:
- 即使沒有寫出正解,也不能影響下面的答題,下面的題目也還是有可能寫出正解。
- 在暴力和部分分數打完之后,剩下知道一定會 \(TLE\) 的點打上亂搞比較好。
- \(dp\) 寫不出要加維!!
回文
還是一個 \(palin\),只不過不太一樣。
一直執着於二維坐標 \(dp\) 的轉移,絲毫忘記了可以增加維度。
我們上來其實有一個 \(\mathcal O(n^4)\) 的想法就是我們直接設置 \(f_{x_1,y1,x_2,y2}\) 代表這個坐標的答案。
但是空間完全承受不住。
我們考慮減小維度。
發現其實只有步數一樣的位置才是有效的。
所以這個就可以壓縮成為三維 \(f_{k,x_1,x_2}\) 表示走了 \(k\) 步,然后第一個坐標的 \(x\) 為 \(x_1\),然后第二個為 \(x_2\)
這個就很好轉移了。
我們確定了步數還有 \(x\),那么我們就可以確定 \(y\)
對於從左上開始的,那么就是 \(y_1 = len+2-x_1\),然后從右下開始的,就是 \(y_2 = n - x_2 + m - len\)。
之后枚舉坐標愉快轉移。
只有相同的位置可以轉移。
話說然后就被卡常了。。。
循環展開真是一個好方法。。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
const int mod = 993244853;
int f[510][510][510];
char s[510][510];
int n,m;
const int dx1[] = {1,0},dy1[] = {0,1},dx2[] = {-1,0},dy2[] = {0,-1};
inline short main()
{
#ifdef ONLINE_JUDGE
file(palin);
#endif
io >> n >> m;
try(i,1,n) scanf("%s",s[i]+1);
f[0][1][n] = 1;
if(s[1][1] != s[n][m])
{
puts("0");
return 0;
}
if(n <= 490 and m <= 490)
{
try(len,0,(n+m-1)/2)
{
try(x1,1,n)
{
int y1 = len - x1 + 2;
if(!(x1 >= 1 and x1 <= n and y1 >= 1 and y1 <= m)) continue;
try(x2,1,n)
{
int y2 = n + m - x2 - len;
if(!(x2 >= 1 and x2 <= n and y2 >= 1 and y2 <= m) or s[x1][y1] != s[x2][y2]) continue;
try(t1,0,1)
{
int nx1 = x1 + dx1[t1],ny1 = y1 + dy1[t1];
if(!(nx1 >= 1 and nx1 <= n and ny1 >= 1 and ny1 <= m)) continue;
try(t2,0,1)
{
int nx2 = x2 + dx2[t2],ny2 = y2 + dy2[t2];
if(!(nx2 >= 1 and nx2 <= n and ny2 >= 1 and ny2 <= m)) continue;
if(s[nx1][ny1] == s[nx2][ny2]) (f[len+1][nx1][nx2] += f[len][x1][x2]) %= mod;
}
}
}
}
}
}
else
{
try(len,0,(n+m-1)/2)
{
try(x1,1,n)
{
int y1 = len - x1 + 2;
if(!(x1 >= 1 and x1 <= n and y1 >= 1 and y1 <= m)) continue;
try(x2,1,n)
{
int y2 = n + m - x2 - len;
if(!(x2 >= 1 and x2 <= n and y2 >= 1 and y2 <= m) or s[x1][y1] != s[x2][y2]) continue;
// try(t1,0,1)
{
int nx1 = x1 + dx1[0],ny1 = y1 + dy1[0];
if(!(nx1 >= 1 and nx1 <= n and ny1 >= 1 and ny1 <= m)) continue;
int nx2 = x2 + dx2[0],ny2 = y2 + dy2[0];
if(!(nx2 >= 1 and nx2 <= n and ny2 >= 1 and ny2 <= m)) continue;
if(s[nx1][ny1] == s[nx2][ny2]) (f[len+1][nx1][nx2] += f[len][x1][x2]) %= mod;
nx2 = x2 + dx2[1],ny2 = y2 + dy2[1];
if(!(nx2 >= 1 and nx2 <= n and ny2 >= 1 and ny2 <= m)) continue;
if(s[nx1][ny1] == s[nx2][ny2]) (f[len+1][nx1][nx2] += f[len][x1][x2]) %= mod;
}
{
int nx1 = x1 + dx1[1],ny1 = y1 + dy1[1];
if(!(nx1 >= 1 and nx1 <= n and ny1 >= 1 and ny1 <= m)) continue;
int nx2 = x2 + dx2[0],ny2 = y2 + dy2[0];
if(!(nx2 >= 1 and nx2 <= n and ny2 >= 1 and ny2 <= m)) continue;
if(s[nx1][ny1] == s[nx2][ny2]) (f[len+1][nx1][nx2] += f[len][x1][x2]) %= mod;
nx2 = x2 + dx2[1],ny2 = y2 + dy2[1];
if(!(nx2 >= 1 and nx2 <= n and ny2 >= 1 and ny2 <= m)) continue;
if(s[nx1][ny1] == s[nx2][ny2]) (f[len+1][nx1][nx2] += f[len][x1][x2]) %= mod;
}
}
}
}
}
int ans = 0;
int len = n + m - 2;
try(i,1,n) (ans += f[len/2][i][i]) %= mod;
if(len & 1) try(i,1,n-1) (ans += f[len/2][i][i+1]) %= mod;
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
寫的麻煩了些。。。
快速排序
給了我一堆代碼,之后就按照它說的去做。
然后因為 \(T1\) 調爆了,然后就真的按照他說的做了。。。
然后就暴力分數。
我們使勁觀察一下子,發現其實這個模擬一遍是非常有規律的。
就是我們在排序的時候,其實他就是選擇了最左邊的那個數字為基准,然后在最左邊的數字為 \(nan\) 的時候直接把 \(l\) 往右邊挪了一個。
那么我們就可以開始找規律了。
其實每一個數字到最后都是排好序的,那么我們所需要的就是找到這個的每一個數字后面跟着的有多少個 \(nan\)。
因為對於每一個 \(l\) 為數字的排序遞歸,一定會把比這個數字小的東西放到左邊,並且就不會再有 \(nan\) 跟着了。
所以我們剛開始就可以把每一個 \(nan\) 的位置用樹狀數組加上一個 \(1\),之后我們統計這個數和下一個比他大的數之間的 \(nan\) 的個數,這個就是它身后跟着的 \(nan\) 的個數。
所以還有一個單調棧
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
int n;
class xin_bit
{
private:
#define low(x) (x & -x)
public:
int c1[maxn],c2[maxn];
inline void add(int x,int val) {for(int i=x;i<=n;i+=low(i)) c1[i] += val,c2[i] += x * val;}
inline void upd(int l,int r,int val) {add(l,val); add(r+1,-val);}
inline int ask(int x) {int ret = 0; for(int i=x;i;i-=low(i)) ret += (x + 1) * c1[i] - c2[i]; return ret;}
inline int query(int l,int r) {return ask(r) - ask(l-1);}
}bit;
std::stack<int>st;
int a[maxn];
int mp[maxn],cnt = 0;
class xin_data
{
public:
int val,num,id;
}d[maxn];
char s[maxn];
int nxt[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(qsort);
#endif
int T; io >> T;
while(T--)
{
io >> n; cnt = 0;
try(i,1,n)
{
scanf("%s",s);
if(s[0] == 'n')
{
bit.upd(i,i,1);
a[i] = 0;
}
else
{
a[i] = atoi(s); mp[i] = ++cnt;
d[cnt].val = a[i]; d[cnt].id = i; d[cnt].num = 0;
while(st.size() and a[st.top()] <= a[i]) nxt[st.top()] = i,st.pop();
st.push(i);
}
}
// try(i,1,n) cout<<nxt[i]<<endl;
while(st.size()) nxt[st.top()] = n,st.pop();
int st = 1;
try(i,1,n) if(a[i]) break;
else
{
st ++;
printf("nan ");
}
int pre = 1;
try(i,st,n) if(a[i] >= pre)
{
d[mp[i]].num = bit.query(i,nxt[i]);
pre = a[i];
}
std::sort(d+1,d+cnt+1,[](const xin_data &x,const xin_data &y) {return (x.val == y.val) ? x.id < y.id : x.val < y.val;});
try(i,1,cnt)
{
printf("%d ",d[i].val);
while(d[i].num --) printf("nan ");
}
putchar('\n');
memset(bit.c1,0,sizeof(int) * (n + 1));memset(bit.c2,0,sizeof(int) * (n + 1));
}
return 0;
}
}
signed main() {return xin::main();}
混亂邪惡
這個題目是亂搞過得。
亂搞很簡單,首先我們先一個空着一個得一個 \(-1\) 一個 \(1\),然后看差值。
之后我們每次進行修正,每一次都先 \(rand\) 出來一個位置,讓其根據 \(tot\) 的大小進行變號。
之后就從 \(1\) 到 \(n\) 掃一遍,之后還是那樣子加減。
復雜度真心不知道,但是還是非常快的。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int n,m;
int a[maxn];
int ans[maxn];
std::random_device shit;
inline int randint(int l,int r)
{
std::uniform_int_distribution<>e(l,r);
return e(shit);
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(chaoticevil);
#endif
io >> n >> m; int tot = 0;
try(i,1,n)
{
io >> a[i];
ans[i] = a[i] & 1;
if(ans[i]) tot += a[i];
else tot -= a[i];
}
// std::sort(a+1,a+n+1);
while(tot)
{
int pos = randint(1,n);
// jb(pos);
if(ans[pos]) tot -= a[pos] * 2,ans[pos] = 0;
else tot += a[pos] * 2,ans[pos] = 1;
if(tot > 0)
{
try(i,1,n)
{
if(tot <= 0) break;
if(ans[i]) tot -= a[i] * 2,ans[i] = 0;
}
}
else
{
try(i,1,n)
{
if(tot >= 0) break;
if(!ans[i]) tot += a[i] * 2,ans[i] = 1;
}
}
// jb(tot);
}
puts("NP-Hard solved");
try(i,1,n)
if(ans[i]) printf("1 ");
else printf("-1 ");
putchar('\n');
return 0;
}
}
signed main() {return xin::main();}
校門外歪脖樹上的鴿子
不知道為啥題面這么奇怪。
我只寫了一個大暴力。
就是還是模擬線段樹的操作。
然后肯定 \(T\) 飛了。
但是還是有 \(48pts\) 算是不低的部分分數。
namespace _std還是很良心的,就是每天考試上來一個不是計數就是期望就很淦
[NOIP2018 提高組] 貨幣系統 | P5020
話說因為現在文件太長了,現在按退格都要好長時間。。。
這個題目之前看了老長時間了,然后看到標簽是 \(dp\),然后就望而卻步了。
今天做了一做,發現其實是一個結論題目。
一個似乎是顯然的結論是這個新的東西一定會從原來的序列里面出來。
那么我們還有一個比較顯然的結論就是說如果我們有一個 \(x\) 他可以被表示出來,那么 \(x-a_i\) 也是一定可以被表示出來。
那么事情就變得明朗起來了。
因為每一種貨幣都是無限多的,那么也就是說我們只要做一個可行的完全背包就好了。
然后對於答案如何統計,我們就直接先把答案賦值成為 \(n\),之后從 \(a_1\) 開始一個一個判斷。
發現這個在之前被統計過了那么就直接 ans--
就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
int n;
int a[maxn];
int f[maxn];
inline short main()
{
int T; io >> T;
while(T--)
{
io >> n; int ans = n;
try(i,1,n) io >> a[i];
std::sort(a+1,a+n+1);
f[0] = 1;
try(i,1,n)
{
if(f[a[i]]) ans --;
try(j,a[i],a[n])
f[j] |= f[j - a[i]];
}
memset(f,0,sizeof(int) * (a[n] + 1));
printf("%d\n",ans);
}
return 0;
}
}
signed main() {return xin::main();}
Day -13
說實話,這一篇博客其實被我咕掉了。
但是在 \(Day \;-12\) 的時候來補了。。。
*破門而入
我不會告訴你我其實沒看出來這個是第一類斯特林數。
然后我先是把這個題目放棄了,但是把 \(T2\) 切了之后就回來繼續研究 \(T1\)了。
然后打了一個表,發現了這個 \(dp\) 公式。
所以我的 \(dp\) 就是通過打表推出來的
然后就沒有什么了。。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int mod = 998244353;
int n,k;
int f[3010][3010];
inline short main()
{
#ifdef ONLINE_JUDGE
file(broken);
#endif
io >> n >> k;
f[1][1] = 1;
f[2][1] = 1; f[2][2] = 2;
try(i,3,n)
{
if(i-1) f[i][1] = f[i-1][1] * (i - 1) % mod;
try(j,2,i-1)
{
f[i][j] = f[i-1][j] * (i - 1) % mod + f[i-1][j-1];
f[i][j] %= mod;
}
f[i][i] = f[i-1][i-1] * i % mod;
}
cout<<f[n][k]<<endl;
return 0;
}
}
signed main() {return xin::main();}
翻轉游戲
說實話這個題目真的是水,直接發現如果前面沒有出現過這個字母的話,那么我們直接加上 \(i-1\) 的貢獻。
然后如果出現過的話,那么也就是直接加上前面和這個字母不一樣的字母的個數就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
char s[maxn];
ll ans = 0;
class xin_bit
{
private:
#define low(x) (x & -x)
public:
int c[101];
inline void add(int x) {for(;x<=26;x+=low(x)) ++ c[x];}
inline int query(int x) {int ret = 0; for(;x;x-=low(x)) ret += c[x]; return ret;}
}bit;
inline short main()
{
#ifdef ONLINE_JUDGE
file(turn);
#endif
scanf("%s",s+1);
int n = strlen(s+1); ans = 1;
try(i,1,n)
{
// try(j,1,26) he[i][j] = he[i-1][j];
int temp = bit.query(s[i] - 'a' + 1) - bit.query(s[i] - 'a');
if(!temp)
ans += i - 1;
else
{
// try(j,1,26) if(s[i] - 'a' + 1 != j)
// ans += he[i][j];
ans += bit.query(26) - temp;
}
// he[i][s[i] - 'a' + 1]++;
bit.add(s[i]-'a'+1);
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
奶油蛋糕塔
這個發現其實一共就只有 \(10\) 中的蛋糕形態。
那么我們對於同一種的蛋糕形態,直接把他們合並成為一個,這樣一共就只剩下 \(10\) 個蛋糕了。
之后爆搜就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int u[] = {0,0,0,0,1,1,1,2,2,3},v[] = {0,1,2,3,1,2,3,2,3,3};
int id[10][10];
int n;
std::vector<int>vec[1001];
int tot[101];
int fa[maxn];
inline int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
inline void merge(int x,int y) {fa[find(x)] = find(y);}
int temp[maxn],a[maxn],ans;
inline void check()
{
// try(i,1,10) cout<<a[i]<<' '; cout<<endl;
try(i,0,3) fa[i] = i,temp[i] = 0;
int ret = 0,cnt = 0,odd = 0;
try(i,0,9)
{
cnt = vec[i].size() - a[i];
if(!cnt) continue;
ret += tot[i];
int x = u[i],y = v[i];
temp[x] += cnt; temp[y] += cnt;
merge(x,y);
if(a[i] == 1) ret -= vec[i][0];
else if(a[i] == 2) ret -= vec[i][0] + vec[i][1];
}
try(i,0,3) odd += (temp[i] & 1);
if(odd > 2 or odd == 1) return ; int res = -1;
try(i,0,3) if(temp[i])
{
if(res == -1) res = i;
else if(find(res) != find(i)) return ;
}
ans = std::max(ans,ret);
}
void dfs(int x)
{
if(x == 10)
{
check();
return ;
}
a[x] = 0; dfs(x + 1);
if(vec[x].size())
{
a[x] = 1; dfs(x+1);
if(vec[x].size() >= 2) a[x] = vec[x].size(),dfs(x+1);
}
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(cake);
#endif
io >> n;
id[0][0] = 0; id[0][1] = 1; id[0][2] = 2; id[0][3] = 3;
id[1][1] = 4; id[1][2] = 5; id[1][3] = 6; id[2][2] = 7;
id[2][3] = 8; id[3][3] = 9;
try(i,1,n)
{
int val; char s[10];
io >> val; scanf("%s",s+1);
int l = s[1] - 'W',r; scanf("%s",s+1);
r = s[1] - 'W';
if(l > r) std::swap(l,r);
vec[id[l][r]].push_back(val);
tot[id[l][r]] += val;
// cout<<a[l][r]<<endl;
}
try(i,1,9) std::sort(vec[i].begin(),vec[i].end());
dfs(0);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
多重影分身
直接二分答案然后 \(\mathcal O(n)\;check\) 就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int u[] = {0,0,0,0,1,1,1,2,2,3},v[] = {0,1,2,3,1,2,3,2,3,3};
int id[10][10];
int n;
std::vector<int>vec[1001];
int tot[101];
int fa[maxn];
inline int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
inline void merge(int x,int y) {fa[find(x)] = find(y);}
int temp[maxn],a[maxn],ans;
inline void check()
{
// try(i,1,10) cout<<a[i]<<' '; cout<<endl;
try(i,0,3) fa[i] = i,temp[i] = 0;
int ret = 0,cnt = 0,odd = 0;
try(i,0,9)
{
cnt = vec[i].size() - a[i];
if(!cnt) continue;
ret += tot[i];
int x = u[i],y = v[i];
temp[x] += cnt; temp[y] += cnt;
merge(x,y);
if(a[i] == 1) ret -= vec[i][0];
else if(a[i] == 2) ret -= vec[i][0] + vec[i][1];
}
try(i,0,3) odd += (temp[i] & 1);
if(odd > 2 or odd == 1) return ; int res = -1;
try(i,0,3) if(temp[i])
{
if(res == -1) res = i;
else if(find(res) != find(i)) return ;
}
ans = std::max(ans,ret);
}
void dfs(int x)
{
if(x == 10)
{
check();
return ;
}
a[x] = 0; dfs(x + 1);
if(vec[x].size())
{
a[x] = 1; dfs(x+1);
if(vec[x].size() >= 2) a[x] = vec[x].size(),dfs(x+1);
}
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(cake);
#endif
io >> n;
id[0][0] = 0; id[0][1] = 1; id[0][2] = 2; id[0][3] = 3;
id[1][1] = 4; id[1][2] = 5; id[1][3] = 6; id[2][2] = 7;
id[2][3] = 8; id[3][3] = 9;
try(i,1,n)
{
int val; char s[10];
io >> val; scanf("%s",s+1);
int l = s[1] - 'W',r; scanf("%s",s+1);
r = s[1] - 'W';
if(l > r) std::swap(l,r);
vec[id[l][r]].push_back(val);
tot[id[l][r]] += val;
// cout<<a[l][r]<<endl;
}
try(i,1,9) std::sort(vec[i].begin(),vec[i].end());
dfs(0);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
Day -12
炸沒了。。。
\(T1\) 直接因為對拍數據范圍沒有想好,然后到最后都是一直 \(ac\),然后直接掛沒 \(100pts\)。
之后 \(T3\),還寫掛了,一個破暴力竟然保齡了?!
本以為自己的 \(T4\) 也可以過掉,然后發現實現也不對?!!
估分 \(300pts\) 實際上 \(40pts\) ?!
淦淦淦
石子合並
這個要注意的就是對於正負數據的判斷。
之后我們一定就可以構造出一種方案使得只變動最大最小值的狀態然后使答案最大。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 7e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
auto max = [](int x,int y) {return x > y ? x : y;}; auto min = [](int x,int y) {return x > y ? y : x;};
namespace xin
{
int n;
int a[maxn];
inline int abs(int x) {return x < 0 ? -x : x;}
inline short main()
{
#ifdef ONLINE_JUDGE
file(stone);
#endif
int T; io >> T;
while(T--)
{
io >> n; int he = 0;
int ok1 = 0,ok2 = 0;
try(i,1,n)
{
io >> a[i],he += a[i];
if(a[i] > 0) ok1 = 1;
if(a[i] < 0) ok2 = 1;
}
if(n == 1) {printf("%lld\n",a[1]); continue;}
int ans = -inf;
if(ok2 == 0 and ok1)
{
// debug;
try(i,1,n-1)
ans = std::max(ans,std::max(a[i],a[i+1]) - std::min(a[i],a[i+1]) + he - a[i] - a[i + 1]);
}
else if(ok1 == 0 and ok2)
{
ans = 0;
try(i,1,n) ans += abs(a[i]);
int maxx = -inf;
try(i,1,n) maxx = std::max(maxx,a[i]);
// cout<<ans + 2 * maxx<<endl;
ans += 2 * maxx;
}
else
{
// debug;
ans = 0;
try(i,1,n) ans += abs(a[i]);
}
cout<<ans<<endl;
}
return 0;
}
}
signed main() {return xin::main();}
翻轉游戲
我們這個要求的是區間的交!!!
而不是並!!
所以其實我們對於坐標取 \(max\) 和 \(min\) 就好了。
然后容斥一下。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
auto max = [](int x,int y) {return x > y ? x : y;}; auto min = [](int x,int y) {return x > y ? y : x;};
namespace xin
{
class xin_data
{
public:
int x1,y1,x2,y2;
xin_data(){}
xin_data(int x1,int y1,int x2,int y2):x1(x1),y1(y1),x2(x2),y2(y2){}
inline xin_data cross(const xin_data &x)
{
if(x1 == -1 or x.x1 == -1) return xin_data(-1,0,0,0);
xin_data ret = xin_data(std::max(x1,x.x1),std::max(y1,x.y1),std::min(x2,x.x2),std::min(y2,x.y2));
if(ret.x1 >= ret.x2 or ret.y1 >= ret.y2) ret.x1 = -1;
return ret;
}
inline int get() {return (x2 - x1) * (y2 - y1);}
}d[maxn],pre[maxn],suf[maxn];
int n,q,p;
inline void work()
{
io >> p >> q >> n;
int ans = 0;
try(i,1,n) io >> d[i].x1 >> d[i].y1 >> d[i].x2 >> d[i].y2;
pre[0] = suf[n+1] = xin_data(0,0,p,q);
try(i,1,n) pre[i] = pre[i-1].cross(d[i]);
throw(i,n,1) suf[i] = suf[i+1].cross(d[i]);
try(i,1,n)
{
xin_data temp = pre[i-1].cross(suf[i+1]);
if(~temp.x1) ans += temp.get();
}
if(~suf[n].x1) ans -= (n - 1) * pre[n].get();
cout<<ans<<endl;
}
inline short main()
{
file(carpet);
int T; io >> T;
while(T--) work();
return 0;
}
}
signed main(){return xin::main();}
優美的旋律
但凡學過 \(hash\) 的人都應該會這個題目!!!
但是我保齡了!!!
炸了!!!
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
auto max = [](int x,int y) {return x > y ? x : y;}; auto min = [](int x,int y) {return x > y ? y : x;};
namespace xin
{
int k1,k2;
char s[maxn];
int n;
ull hash[maxn],p[maxn];
inline ull get(int l,int r) {return hash[r] - hash[l-1] * p[r- l + 1];}
int ans = 0;
inline short main()
{
#ifdef ONLINE_JUDGE
file(melody);
#endif
io >> k1 >> k2;
scanf("%s",s+1);
n = strlen(s+1);
p[0] = 1;
try(i,1,n) hash[i] = hash[i-1] * 13331 + (s[i] - 'a' + 1),p[i] = p[i-1] * 13331;
try(l,1,n)
{
try(len,1,n-l)
{
ull st = get(l,l+len-1);
int cnt = 0;
for(int r = l + len - 1;r <= n;r += len)
{
if(get(r - len + 1,r) == st) cnt ++;
else break;
}
if(cnt != 1)ans = std::max(ans,len * k1 + cnt * k2);
// sb(len); sb(cnt); jb(len * k1 + cnt * k2);
}
}
cout<<ans<<endl;
return 0;
}
}
signed main(){return xin::main();}
基站建設
正解並非如此,但我是枚舉第一個然后枚舉度數之后選擇最大的兩個來做的。
之后還非常快。。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
auto max = [](int x,int y) {return x > y ? x : y;}; auto min = [](int x,int y) {return x > y ? y : x;};
namespace xin
{
std::bitset<50001>bit[50001],temp;
std::vector<int>vec[50001];
int n,m;
class xin_data
{
public:
int x,y;
}d[maxn];
int r[maxn],a[maxn];
int ans = 0;
inline short main()
{
#ifdef ONLINE_JUDGE
file(station);
#endif
io >> n >> m;
try(i,1,n) io >> r[i];
try(i,1,m)
{
register int x,y; io >> x >> y;
vec[x].emplace_back(y); vec[y].emplace_back(x);
bit[x][y] = 1; bit[y][x] = 1;
}
try(i,1,n) std::sort(vec[i].begin(),vec[i].end(),[&](int x,int y) {return r[x] > r[y];});
try(i,1,n) if(vec[i].size() >= 2)
{
for(auto v1 : vec[i])
{
int cnt = 0;
for(auto v2 : vec[i]) if(v1 != v2)
{
if(bit[v1][v2]) a[++cnt] = v2;
if(cnt == 2) break;
}
if(cnt < 2) continue;
ans = std::max(ans,(r[i] + 1) * (r[v1] + 1) + r[a[1]] * r[a[2]]);
// debug;
// sb(a[1]); jb(a[2]);
// jb((r[i] + 1) * (r[v1] + 1) + r[a[1]] * r[a[2]]);
}
}
cout<<ans<<endl;
return 0;
}
}
signed main(){return xin::main();}
Day -11
話說你們可能不相信
我改完題了。。
改了一題
NOIP 2018
被卡常了。
首先發現答案是有單調性的。
然后我們就可以二分答案。
關鍵就是該怎么去 \(check\)。
其實有一個顯然的 \(loglog\) 的做法。
然后應該是過不去。
然后經過 \(APJifengc\) 的 \(nb\) 卡常三分做法。
然后比他的 \(log\) 快
就是在固定答案之后。
容易發現這個東西是一個二次函數,之后三分購買第一個的個數。
然后所以我們找到最低的點就能判斷這個答案是否可行。
那么直接一個三分就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int a,b,c,d;
int x;
// auto ws = [](int x) {int ret = 0;while(x) ret ++,x /=10; return ret;};
inline auto get1(int x)
{
__uint128_t ret = x - 1; ret *= x; ret /= 2; ret *= b;
__uint128_t temp = a; temp *= x; ret += temp;
return ret;
// return (x - 1) * x / 2 * b + a * x;
}
inline auto get2(int x)
{
__uint128_t ret = x - 1; ret *= x; ret /= 2; ret *= d;
__uint128_t temp = c; temp *= x; ret += temp;
return ret;
// return (x - 1) * x / 2 * d + c * x;
}
// inline int wei1(int x) {return ws(x) * 2 + ws(b);}
// inline int wei2(int x) {return ws(x) * 2 + ws(b);}
auto check = [](int k) -> bool
{
// int temp2 = (2 * a - b - d * k - 2);
// int temp1 = b / 2;
// int ret = -(temp2 / (temp1));
// return get1(ret) + get2(k - ret) <= x;
int l = 0,r = k;
// if((get1(0) + get2(k) <= x) or (get1(k) + get2(0) <= x)) return 1;
while(r - l >= 10)
{
// register int mid1 = (r - l + 1) / 3 + l,mid2 = r - (r - l + 1) / 3;
register int mid1 = ((l + r) >> 1) , mid2 = mid1 + 1;
auto com1 = get1(mid1) + get2(k - mid1),com2 = get1(mid2) + get2(k - mid2);
if(com1 > com2)
{
if(com2 <= x) return 1;
l = mid1;
}
else
{
if(com1 <= x) return 1;
r = mid2;
}
}
try(i,l,r)
{
if(get1(i) + get2(k - i) <= x) return 1;
}
return 0;
};
int wb;
auto ws = [](int x) {int ret = 0;while(x) ret ++,x /=10; return ret;};
auto check1 = [](int k) -> bool
{
if(ws(k) * 2 + wb >= 20) return 1;
__int128 ret = b; ret *= k; ret *= k;
ret += (2 * a - b) * k;
return ret > x;
};
inline short main()
{
#ifdef ONLINE_JUDGE
file(money);
#endif
int T; io >> T;
while(T--)
{
io >> a >> b >> c >> d >> x;
int cnt1 = 0,cnt2 = 0;
if((x / b <= (int)(1e7) or x / d <= (int)(1e7)) and d >= 5 and b >= 5)
{
// debug;
while(x >= 0)
{
while(x >= 0 and b * cnt1 + a <= d * cnt2 + c)
x -= b * cnt1 + a,cnt1 ++;
while(x >= 0 and b * cnt1 + a > d * cnt2 + c)
x -= d * cnt2 + c,cnt2 ++;
}
// sb(cnt1); jb(cnt2);
printf("%lld\n",cnt1 + cnt2 - 1);
continue;
}
int l = 0,r = inf * 2;
while(l != r - 1 and l < r)
{
register int mid = l + r >> 1;
if(check(mid)) l = mid;
else r = mid;
}
if(check(r)) printf("%lld\n",r);
else printf("%lld\n",l);
}
return 0;
}
}
signed main() {return xin::main();}
Day -10
P1941 [NOIP2014 提高組] 飛揚的小鳥
這個題目首先發現這個答案是有單調性的。
那么我們的想法就是可以先二分答案。
然后發現做不出來
所以不是二分答案。。。
那么我們換一種思路,發現每次按上鍵的次數是無限的,這個似乎就相當於一個完全背包。
然后只能最多有一次掉落,那么也就是相當於 \(01\) 背包。
那么其實這個題目也就非常明朗了。
設 \(f_{i,j}\) 表示走到 \(i\) 這個坐標,之后高度為 \(j\) 的最小次數。
那么:
最后的這個方程就是表示最大的高度只能是 \(m\)。
之后我們考慮有管道的情況,這個直接設置成為 \(\inf\) 就行了
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
int n,m,k;
class xin_data
{
public:
int x,xia,shang;
}d[maxn];
int f[2][maxn];
int up[maxn],down[maxn];
inline int min(int x,int y) {return x > y ? y : x;}
inline short main()
{
io >> n >> m >> k;
try(i,1,n) io >> up[i] >> down[i];
try(i,1,k) io >> d[i].x >> d[i].xia >> d[i].shang;
std::sort(d+1,d+k+1,[&](const xin_data &x,const xin_data &y) {return x.x < y.x;});
int zhi = 1;
try(i,1,n)
{
int cur = i & 1,lst = cur ^ 1;
memset(f[cur],0x3f,sizeof(int) * (m + 1));
try(j,up[i]+1,up[i]+m) f[cur][j] = min(f[cur][j-up[i]],f[lst][j-up[i]]) + 1;
// for(int j=up[i]+1;j<=up[i]+m;j++)//p=1,完全背包
// f[i%2][j]=min(f[i%2^1][j-up[i]]+1,f[i%2][j-up[i]]+1);
try(j,m+1,m+up[i]) f[cur][m] = min(f[cur][m],f[cur][j]);
try(j,1,m-down[i]) f[cur][j] = min(f[cur][j],f[lst][j+down[i]]);
if(i == d[zhi].x)
{
try(j,0,d[zhi].xia) f[cur][j] = inf;
throw(j,m,d[zhi].shang) f[cur][j] = inf;
int ans = inf;
try(j,1,m) ans = min(ans,f[cur][j]);
if(ans >= inf)
{
printf("0\n%d\n",zhi - 1);
return 0;
}
++zhi;
}
// jb(i);
// try(j,1,m) cout<<f[cur][j]<<' ';
// cout<<endl;
}
int ans = inf;
try(j,1,m) ans = min(ans,f[n & 1][j]);
cout<<1<<endl<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
CF 1572C
關於區間上的問題,還是考慮區間 \(dp\) 來解決。
我們發現一個連續的長串的相同顏色是沒有什么用的。
所以直接把序列去重就行了。
之后我們考慮一個結論:
我們把整個序列都變成兩個端點上面的其中一個顏色一定不劣。
證明:
因為端點是和其他的點沒有什么關系的,所以無論前面的怎么搞,最后的端點一定還是要變色。
那么不如在搞掉前面所有點的顏色之后直接再把前面的顏色都變成端點的顏色。
有了這個結論,那么其實這個題目就簡單很多了, \(dp\) 方程也是從這個上面轉過來的。
我們設 \(f_{i,j}\) 表示 \(i\) 到 \(j\) 這個區間,之后把這個區間都變成 \(c_j\) 這個顏色的最小次數。
那么:$$f_{i,j} = \min(f_{i+1,j},f_{i,j-1})+1$$。
之后還有一種情況,就是說如果這個序列當中有相同的顏色,那么這個就不是最優的。
這時候只要找到那個相同的顏色的上一個,位置記為 \(k\),那么 \(f_{i,j} = \min(f_{i,k}+f_{k+1,j})\)。
這樣就能保證最小了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
int f[3010][3010];
int a[maxn],pre[maxn];
int vis[maxn];
inline short main()
{
int T; io >> T;
while(T--)
{
int m,n = 0; io >> m;
try(i,1,m) io >> a[i],pre[a[i]] = vis[a[i]] = 0;
n = std::unique(a+1,a+m+1) - (a + 1);
// try(i,1,n) cout<<a[i]<<' '; cout<<endl;
try(i,1,n) pre[i] = vis[a[i]],vis[a[i]] = i;//,sb(i),jb(pre[i]);
try(i,1,n) try(j,1,n) f[i][j] = inf;
try(i,1,n) f[i][i] = 0,f[i+1][i] = 0;
try(len,2,n)
{
try(i,1,n-len+1)
{
register int j = i + len - 1;
f[i][j] = std::min(f[i+1][j],f[i][j-1]) + 1;
for(int k=pre[j];k>=i;k=pre[k])
f[i][j] = std::min(f[i][j],f[i][k]+f[k+1][j]);
}
}
// try(i,1,n) try(j,i,n) sb(i),sb(j),jb(f[i][j]);
printf("%d\n",f[1][n]);
}
return 0;
}
}
signed main() {return xin::main();}
P2822 [NOIP2016 提高組] 組合數問題
其實本來以為這個東西有一個很厲害的結論的。
但是其實數據范圍很小,\(n^2\) 遞推加 \(\mathcal O(1)\) 回答即可。
首先暴力的做法還是比較顯然的,既然我們要求能夠整除 \(k\) 的組合數,那么我們的思路一定就是直接 \(mod\;k\),之后為 \(0\) 的就是有貢獻的。
那么因為只有 \(2000\) 我們預處理出來所有的組合數之后取前綴和。
因為模數很可能不是質數,所以我們要用楊輝三角。
還有要注意的是這個預處理出來的是一個三角矩陣,計算前綴和的時候我們要保證 \(!c_{i,j}\;and\;j\leq i\)
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
int c[2010][2010];
int he[2010][2010];
int k,n,m;
inline short main()
{
int T; io >> T >> k;
try(i,0,2000)
{
c[i][0] = 1;
try(j,1,i) c[i][j] = c[i-1][j] + (c[i-1][j-1]),c[i][j] %= k;
}
try(i,1,2000)
{
try(j,1,2000)
he[i][j] = he[i-1][j] + he[i][j-1] - he[i-1][j-1] + (!c[i][j] and j <= i);
}
// jb(he[2000][2000]);
while(T--)
{
io >> n >> m;
m = std::min(n,m);
printf("%d\n",he[n][m]);
}
return 0;
}
}
signed main() {return xin::main();}
P1220 關路燈
一個上來感覺是背包,但是實際上還是一個區間 \(dp\) 的題目。
范圍 \(n\leq 50\),其實這個范圍感覺很迷,絲毫不知道從哪里下手。
但是就是完全不能夠爆搜
我們設 \(f_{i,j}\) 為關閉了 \(i\) 到 \(j\) 的電燈的答案。
那么就很顯然 \(f_{1,n}\) 就是我們的目標。
因為要取 \(\min\) 所以自然 \(f_{pos,pos}=0\)。
但是其實這個樣子是沒有辦法去轉移的。
那么我們再加維。
\(f_{i,j,0/1}\) 這個就代表關完這些燈之后老王在左(0)右(1)。
那么轉移就顯然了。
f[i][j][0]=std::min(f[i+1][j][0] + (a[i+1] - a[i]) * (he[n] - (he[j] - he[i])),f[i+1][j][1] + (a[j] - a[i]) * (he[n] - (he[j] - he[i]))));
f[i][j][1]=std::min(f[i][j-1][0] + (a[j] - a[i]) * (he[n] - (he[j-1] - he[i-1])),f[i][j-1][1] + (a[j] - a[j-1]) * (he[n] - (he[j-1] - he[i-1]))));
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
void chkmax(int &x,int y) {x = x > y ? x : y;} void chkmin(int &x,int y) {x = x > y ? y : x;}
namespace xin
{
int n,pos;
int f[51][51][2];
int a[maxn],b[maxn];
int he[maxn];
inline short main()
{
io >> n >> pos;
try(i,1,n) io >> a[i] >> b[i],he[i] = he[i-1] + b[i];
memset(f,0x3f,sizeof(f));
f[pos][pos][1] = f[pos][pos][0] = 0;
try(len,2,n)
{
try(i,1,n - len + 1)
{
int j = i + len - 1;
chkmin(f[i][j][0],std::min(f[i+1][j][0] + (a[i+1] - a[i]) * (he[n] - (he[j] - he[i])),f[i+1][j][1] + (a[j] - a[i]) * (he[n] - (he[j] - he[i]))));
chkmin(f[i][j][1],std::min(f[i][j-1][0] + (a[j] - a[i]) * (he[n] - (he[j-1] - he[i-1])),f[i][j-1][1] + (a[j] - a[j-1]) * (he[n] - (he[j-1] - he[i-1]))));
}
}
cout<<std::min(f[1][n][1],f[1][n][0])<<endl;
return 0;
}
}
signed main() {return xin::main();}
復習了歐拉函數的線性篩法。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
void chkmax(int &x,int y) {x = x > y ? x : y;} void chkmin(int &x,int y) {x = x > y ? y : x;}
namespace xin
{
int phi[maxn],pri[maxn];
bool vis[maxn];
int tot;
inline void shai(int ms)
{
phi[1] = 1;
try(i,2,ms)
{
if(!vis[i]) pri[++tot] = i,phi[i] = i - 1;
for(int j=1;pri[j] * i <= ms and j <= tot;++j)
{
vis[pri[j] * i] = 1;
if(i % pri[j]) phi[i * pri[j]] = phi[i] * phi[pri[j]];
else{phi[i * pri[j]] = phi[i] * pri[j]; break;}
}
}
}
inline short main()
{
return 0;
}
}
signed main() {return xin::main();}
[NOIP2014 提高組] 解方程 | P2312
其實這個題目就是唬人,並不是很難。
發現輸入就是一個高精度的數,但是其實我們只需要它 \(mod\) 上一個數就好了。
那么就很好辦。
之后我們發現其實 \(m\) 就有 \(10^6\),直接暴力枚舉,然后判斷。
\(n\) 雖然只有 \(100\),但是如果這個 \(n\) 次多項式如果使用快速冪暴力計算的話,復雜度直接無法接受。
所以我們把這個多項式試圖優化成 \(\mathcal O(n)\) 計算。
如何優化???
那么最后從 \(n\) 到 \(1\) 直接就能 \(\mathcal O(n)\) 計算了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch - '0'),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int mod = 998244353;
int n,m;
int a[maxn];
char s[maxn];
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
}
inline bool calc(int x)
{
int ret = 0;
throw(i,n,1) ret = (ret + a[i]) * x % mod;
return !((ret + a[0]) % mod);
// int ret = a[0];
// try(i,1,n) ret += (a[i] * ksm(x,i) % mod),ret -= (ret >= mod) ? mod : 0;
// return !ret;
}
int ans[maxn],zhi = 0;
inline short main()
{
io >> n >> m;
// sb(n); jb(m);
try(i,0,n)
{
scanf("%s",s+1);
int len = strlen(s + 1);
int ret = 0;
if(s[1] == '-')
{
try(j,2,len) ret = ret * 10 + (s[j] - '0'),ret %= mod;
a[i] = (-ret + mod) % mod;
// jb(a[i]);
}
else
{
try(j,1,len) ret = ret * 10 + (s[j] - '0'),ret %= mod;
a[i] = ret;
// jb(a[i]);
}
// sb(i); jb(a[i]);
}
// debug;
try(i,1,m) if(calc(i)) ans[++zhi] = i;
printf("%lld\n",zhi);
try(i,1,zhi)
printf("%lld\n",ans[i]);
return 0;
}
}
signed main() {return xin::main();}
復習了高斯消元,發現還是有一些細節打不對。。。
try(j,1,n) if(i xor j)
{
if(fabs(a[i][i]) <= 1e-8) return !printf("No Solution");
double temp = a[j][i] / a[i][i];
try(k,i,n+1)
{
a[j][k] -= a[i][k] * temp;
}
}
每次去消的應該是 \(j\) 行,而不是 \(i\) 行。
Day -9
僅有 \(9\) 天了。
開掛
我們其實能夠直接確定這是一個貪心。
數據范圍很大,所以最多帶一個 \(log\)。
排序是一定需要的,之后我們就是要找到最小的方案。
這樣我們只要讓這些東西的差值乘上最小的 \(b\),就好了。
用三個棧維護一下就能在這一部分做到 \(\mathcal O(n)\) 了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int a[maxn],b[maxn];
int n;
class xin_data
{
public:
int x,y;
}d[maxn];
int cnt = 0;
int st1[maxn],st2[maxn],st3[maxn];
int zhi1,zhi2,zhi3;
int tot = 0;
inline short main()
{
#ifdef ONLINE_JUDGE
file(openhook);
#endif
io >> n;
try(i,1,n) io >> a[i]; try(i,1,n) io >> b[i];
std::sort(a+1,a+n+1); std::sort(b+1,b+n+1);
a[n+1] = INT_MAX; int size = 0;
try(i,1,n) if(a[i] == a[i+1])
{
st1[++zhi1] = a[i];
++size;
}
else
{
if(!zhi1) continue;
if(a[i] + 1 != a[i+1])
{
if(a[i+1] - a[i] - 1 > size)
{
try(j,a[i]+1,a[i]+size) st2[++zhi2] = j;
size = 0;
st3[++zhi3] = st2[zhi2--];
while(zhi1)
{
while(zhi2 and st1[zhi1] < st2[zhi2])
{
st3[++zhi3] = st2[zhi2--];
}
d[++cnt] = xin_data{st1[zhi1--],st3[zhi3--]};
}
}
else
{
try(j,a[i]+1,a[i+1]-1) st2[++zhi2] = j;
size -= (a[i+1] - a[i] - 1);
}
}
}
// jb(cnt);
// try(i,1,cnt) cout<<d[i].x<<' '<<d[i].y<<endl;
std::sort(d+1,d+cnt+1,[&](const xin_data &x,const xin_data &y){return x.y - x.x > y.y - y.x;});
ull ans = 0;
// jb(zhi1);
// jb(cnt);
try(i,1,cnt) ans += 1ull * (d[i].y - d[i].x) * b[i];
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
叄仟柒佰萬
也是一個 \(\mathcal O(n)\) 的題目,只不過這個是一個 \(dp\)。
我們考慮整個序列所能構成的合法的方案的 \(mex\) 一定會是唯一的。
所以我們直接找前面 \(mex\) 值等於那個 \(K\) 的 \(f_j\) 來轉移就好了。
這樣是 \(\mathcal O(n^2)\) 的,取一個前綴和優化成 \(\mathcal O(n)\)
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 4e7+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
const int mod = 1e9+7;
int f[maxn];
int a[maxn];
int n;
int mex = 0;
int vis[maxn];
#define fmod(x) (x -= (x >= mod) ? mod : 0)
inline short main()
{
#ifdef ONLINE_JUDGE
file(clods);
#endif
int T; io >> T;
while(T--)
{
io >> n; mex = 0;
if(n == 37000000)
{
int x,y; io >> x >> y;
a[1] = 0; vis[0] ++;
try(i,2,n)
{
a[i] = (a[i-1] * x + y + i) & 262143;
vis[a[i]] ++;
}
}
else
{
memset(vis,0,sizeof(int) * (n + 2));
try(i,1,n) io >> a[i],vis[a[i]] ++,f[i] = 0;
}
while(vis[mex]) mex ++;
memset(vis,0,sizeof(int) * (mex));
try(i,mex+1,n) vis[i] = n + 1;
f[0] = 1;
int l = 1,temp = 0;
try(i,1,n)
{
if(!vis[a[i]]) ++ temp;
vis[a[i]] ++;
if(temp == mex)
{
for(;(l xor i) and vis[a[l]] > 1;++l)
vis[a[l]] --;
f[i] = f[i-1] + f[l-1];
fmod(f[i]);
}
else f[i] = f[i-1];
}
cout<<(f[n] - f[n-1] + mod) % mod<<endl;
}
return 0;
}
}
signed main() {return xin::main();}
Day -8
[TJOI2013] 獎學金 | P3963
這個求中位數的題目我們考慮向左右塞數。
首先想到了一個二分答案的思路,發現 \(naive\) 得一批。
之后發現其實我們只要預處理出來每一個數作為中位數的代價就可以很快得到答案。
考慮用堆來維護這個值,見到大的就彈出來,保證里面有 \(\frac{n}{2}\) 個數並且最小就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
class xin_data
{
public:
int x,y;
}d[maxn];
int n,c,f;
std::priority_queue<int>q1,q2;
int he1[maxn],he2[maxn];
inline short main()
{
io >> c >> n >> f;
try(i,1,n) io >> d[i].x >> d[i].y;
std::sort(d+1,d+n+1,[&](const xin_data &x,const xin_data &y){return x.x < y.x;});
int l = c / 2 + 1,r = n - c / 2;
int sum = 0;
// try(i,1,n) sb(i),sb(d[i].x),jb(d[i].y); cout<<endl;
try(i,1,l-1) q1.push(d[i].y),sum += d[i].y;
try(i,l,n)
{
he1[i] = sum;
if(d[i].y < q1.top()) sum -= q1.top(),q1.pop(),sum += d[i].y,q1.push(d[i].y);
}
sum = 0;
try(i,r+1,n) q2.push(d[i].y),sum += d[i].y;
throw(i,r,1)
{
he2[i] = sum;
if(d[i].y < q2.top()) sum -= q2.top(),q2.pop(),sum += d[i].y,q2.push(d[i].y);
}
// try(i,1,n) sb(i),sb(he1[i]),jb(he2[i]);
// sb(l);jb(r);
throw(i,r,l) if(he1[i] + he2[i] + d[i].y <= f) return cout<<d[i].x<<endl,0;
cout<<-1<<endl;
return 0;
}
}
signed main() {return xin::main();}
嗑瓜子
上來發現這個題目還是一個期望。
然后開始害怕。。。
然后發現不會。。。
之后發現這個其實可以轉移概率。
\(f_{i,j}\) 就表示走了 \(i\) 步,之后拿了 \(j\) 瓜子的概率。
所以這個直接就能夠 \(\mathcal O(1)\) 轉移。
因為知道了步數和瓜子之后,那么現在剩下的瓜子皮和總數其實也就知道了。
那么我們就可以進行轉移了,我們假設 \(get1\) 為現在這個狀態拿到瓜子皮的概率,\(get2\) 就是拿到瓜子的概率。
那么轉移:
if(j - 1 == n) f[i][j] = f[i-1][j] * get1(i-1,j) % mod;
else if(j == n) f[i][j] = f[i-1][j-1] * get2(i-1,j-1) % mod;
else f[i][j] = f[i-1][j-1] * get2(i-1,j-1) % mod + f[i-1][j] * get1(i-1,j) % mod;
這個其實就是轉移了一個概率,但是並沒有轉移什么期望。
所以真正的答案是:
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int mod = 998244353;
int f[6010][2010];
int n;
int inv[maxn];
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
}
inline int get1(int x,int y)
{
if(n - x + 2 * y < 0) return 0;
return (n - x + 2 * y - (n - y)) * inv[n - x + 2 * y] % mod;
}
inline int get2(int x,int y)
{
if(n - x + 2 * y < 0) return 0;
return (n - y) * inv[n - x + 2 * y] % mod;
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(eat);
#endif
io >> n;
inv[0] = inv[1] = 1;
try(i,2,3*n) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
f[1][1] = 1;
// jb(inv[3]);
// jb(get2(2,1));
try(i,2,3*n)
{
int ms = std::min(i,n);
bool ok = 1;
try(j,1,ms)
{
// sb(i); jb(j);
if(j - 1 == n) f[i][j] = f[i-1][j] * get1(i-1,j) % mod;
else if(j == n) f[i][j] = f[i-1][j-1] * get2(i-1,j-1) % mod;
else
f[i][j] = f[i-1][j-1] * get2(i-1,j-1) % mod + f[i-1][j] * get1(i-1,j) % mod;
// if(i == 3 and j == 1) jb(f[i-1][j] * (n - j) % mod * get1(i-1,j) % mod),jb(f[3][1]);
f[i][j] %= mod;
if(f[i][j]) ok = 0;
}
// if(ok) while(1) jb(i);
}
// jb(f[2][0]);
// try(i,1,3*n)
// {
// // try(j,1,i) sb(i),sb(j),jb(f[i][j]);
// try(j,1,i) if(f[i][j] < 0) while(1) debug;
// // bool ok = 1;
// // try(j,1,i) if(f[i][j]) {ok = 0; break;}
// // if(ok) while(1) jb(i);
// // cout<<endl;
// }
int ans = 0;
try(i,n,3*n) ans += f[i][n] * i % mod,ans %= mod;
cout<<ans<<endl;
// jb(sizeof(f) / (1024 * 1024));
return 0;
}
}
signed main() {return xin::main();}
第 k 大查詢
首先一定會有一個 \(n^2log\) 的暴力。
一個主席樹來維護。
之后還有 \(20pts\) 的單調棧部分分數。
那么現在考慮一下正解。
我們讓某個數成為那個第 \(k\) 個,那么我們就需要找到 \(k-1\) 個比他大的數。
那么我們就用兩個指針來卡一下邊界。
如果從最小的開始向上來做,那么前面的數一定不會有貢獻,但是我們還是要算上。
這樣的話我們用一個 \(pre\) \(next\) 來模擬鄰接表。
這樣的話就是我們就會把之前刪除的東西都跳過去。
那么這個的貢獻就是 \(next_x - x\)
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int a[maxn];
int pos[maxn];
int n,ans,k;
int nxt[maxn],pre[maxn];
bool vis[maxn];
inline void check(int x)
{
// jb(x);
int cnt = 0,l = 1,r = n;
for(int i=pos[x];i;i=pre[i])
{
cnt += (a[i] > x);
l = i;
if(cnt == k - 1) {break;}
}
r = pos[x];
if(cnt != k - 1)
{
for(int i=pos[x];i<=n;i=nxt[i])
{
cnt += (a[i] > x);
r = i;
if(cnt == k - 1) {break;}
}
if(cnt != k - 1) return;
}
cnt = 0;
// sb(l); jb(r);
// try(i,1,n) sb(i),cout<<nxt[i]<<' '<<pre[i]<<endl;
while(1)
{
if(l > pos[x] or r > n) break;
cnt += (l - pre[l]) * (nxt[r] - r);
l = nxt[l]; r = nxt[r];
}
nxt[pre[pos[x]]] = nxt[pos[x]]; pre[nxt[pos[x]]] = pre[pos[x]];
// jb(cnt);
ans += cnt * x;
// jb(ans);
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(kth);
#endif
io >> n >> k;
try(i,1,n) io >> a[i],pos[a[i]] = i,nxt[i] = i + 1,pre[i] = i - 1;
try(i,1,n) check(i);
// check(1); check(2);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
樹上路徑
相當於把每個邊拆開求一遍直徑。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
std::vector<int>vec[maxn>>1];
int n;
int v[maxn],vis[maxn];
int rt,maxx,now;
int f[maxn],mp[maxn],maxval[maxn];
void dfs(int x,int fa,int dis,bool fg)
{
f[x] = fa; vis[x] = fg;
if(dis > maxx) maxx = dis,now = x;
for(auto y : vec[x]) if(y != fa and !v[y])
dfs(y,x,dis+1,fg);
}
int dfs1(int x,int fa)
{
int mx = 0;
for(auto y : vec[x]) if(y != fa and !v[y])
mx = std::max(mx,dfs1(y,x));
return mx + 1;
}
std::vector<int>a;
int mx_dis[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(tree);
#endif
io >> n;
try(i,1,n-1)
{
register int x,y; io >> x >> y;
vec[x].emplace_back(y); vec[y].emplace_back(x);
}
rt = 1; maxx = 0;
dfs(rt,0,1,0);
rt = now; maxx = 0;
dfs(rt,0,1,0);
for(int i=now;i;i=f[i]) v[i] = 1,a.emplace_back(i);
for(auto x : a) mx_dis[x] = dfs1(x,0);
int temp = 0;
try(i,1,n)
if(v[i] == 0 and vis[i] == 0)
{
now = maxx = 0;
dfs(i, 0, 1, 0); dfs(now, 0, 1, 1);
temp = std::max(temp,maxx);
}
mp[a.size()] = temp;
mp[temp] = a.size(); maxval[a.size()] = 0;
throw(i,a.size()-2,0) maxval[i + 1] = std::max(maxval[i + 2],(int)a.size() - i - 2 + mx_dis[a[i + 1]]);
try(i,0,a.size()-1)
{
int x = i + mx_dis[a[i]];
int y = maxval[i + 1];
mp[x] = std::max(mp[x], y);
mp[y] = std::max(mp[y], x);
}
int ans = 0; maxx = 0;
throw(i,a.size(),1)
{
maxx = std::max(maxx, mp[i]);
ans += maxx;
}
printf("%lld\n", ans);
return 0;
}
}
signed main() {return xin::main();}
糖
現在僅有一個 \(40pts\) 的暴力想法。
我們定義 \(f_{i,j}\) 為現在走到了 \(i\),之后手上有 \(j\) 塊糖。
但是這個現在還沒有 \(\mathcal O(1)\) 的轉移,只有一個 \(\mathcal O(c)\) 的轉移。
這個轉移就是我們枚舉 \(k\),之后多則 \(sell\),少則 \(buy\)
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int a[maxn];
class xin_data
{
public:
int buy,sell;
}d[maxn];
int f[1001][1001];
int n,c;
#define min(x,y) (x > y ? y : x)
inline short main()
{
#ifdef ONLINE_JUDGE
file(candy);
#endif
io >> n >> c;
try(i,1,n) io >> a[i];
try(i,0,n-1) io >> d[i].buy >> d[i].sell;
memset(f,0x3f,sizeof(f));
try(j,0,c) f[0][j] = d[0].buy * j;
try(i,1,n)
{
// jb(i);
int x = a[i] - a[i-1];
try(j,0,c)
{
try(k,x,c)
{
if(k - x >= j) //sell
f[i][j] = min(f[i][j],f[i-1][k] - (k - x - j) * d[i].sell);
else //buy
f[i][j] = min(f[i][j],f[i-1][k] + (j - (k - x)) * d[i].buy);
// sb(i); sb(j); sb(k); sb(f[i-1][k]); jb(f[i][j]);
}
}
// try(k,1,c) f[i][k] = f[i][0] + d[i].buy * k;
// try(j,0,c)
// {
// try(k,j+1,c)
// f[i][j] = std::min(f[i][j],f[i][k] - (k - j) * d[i].sell);
// }
}
int ans = llinf;
// try(i,0,n)
// {
// try(j,0,c) cout<<f[i][j]<<' ';
// cout<<endl;
// }
try(i,0,c) ans = min(f[n][i],ans);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
Day -7
確實僅有 \(7\) 天了。
[USACO3.3]家的范圍 Home on the Range | P2733
感覺這個題目的思路還是比較妙的。
我們想要找到一個邊長是 \(len\),右下角是 \((i,j)\) 的矩形是否合法。
那么我們只需要判斷邊長是 \(len-1\),右下角分別為 \((i-1,j),(i,j-1),(i-1,j-1)\) 的矩形是不是合法就行了。
當然還要看當前位置是不是 \(1\)。
之后因為需要求出每一種矩形的個數。
那么我們得出每一個 \(f_{len,i,j}\) 之后統計答案就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
#define min(a,b) (a > b ? b : a)
int n;
char s[maxn];
int a[251][251];
bool f[251][251][251];
inline short main()
{
scanf("%lld",&n);
try(i,1,n)
{
scanf("%s",s+1);
try(j,1,n) a[i][j] = s[j] - '0',f[1][i][j] = a[i][j];
}
try(len,2,n)
{
try(i,1,n) try(j,1,n)
f[len][i][j] = min(min(a[i][j],f[len-1][i-1][j]),min(f[len-1][i][j-1],f[len-1][i-1][j-1]));
}
// try(i,1,n)
// {
// try(j,1,n)
// cout<<f[1][i][j]<<' ';
// cout<<endl;
// }
// cout<<endl;
// try(i,1,n)
// {
// try(j,1,n)
// cout<<f[2][i][j]<<' ';
// cout<<endl;
// }
try(len,2,n)
{
int ans = 0;
try(i,1,n) try(j,1,n) ans += f[len][i][j];
if(ans) printf("%lld %lld\n",len,ans);
}
return 0;
}
}
signed main() {return xin::main();}
樹上排列
其實這個題目如果能夠想到 \(hash\) 其實應該是不難的。
但是我確實沒有想到,但是謝了一個 \(nb\) 的暴力過掉了這個題目。
對於一個排列,那么我們想到這個東西成立必須保證:
- 不能有重復。
- 不能大於len
其實這兩個點就夠了。
所以我們再跳的時候時刻判斷就好了。
正解的做法可以胡一下,其實就是我們把每一個 \(1\) ~ \(n\) 的序列都賦上一個 \(hash\)
之后直接維護區間乘法或者乘法和加法。
brute code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],cnt_b;
inline void add(int x,int y) {edge[++cnt_b].ver = y; edge[cnt_b].next = head[x]; head[x] = cnt_b;}
int n,qnum;
int a[maxn];
int d[maxn],fa[maxn],top[maxn],siz[maxn],hson[maxn];
void dfs1(int x,int f)
{
fa[x] = f; d[x] = d[f] + 1; siz[x] = 1;
go(i,x) if(y != f)
{
dfs1(y,x);
siz[y] += siz[x];
if(siz[y] > siz[hson[x]]) hson[x] = y;
}
}
void dfs2(int x,int t)
{
top[x] = t;
if(hson[x]) dfs2(hson[x],t);
go(i,x)
{
if(y == fa[x] or y == hson[x]) continue;
dfs2(y,y);
}
}
inline int lca(int x,int y)
{
while(top[x] xor top[y])
{
if(d[top[x]] < d[top[y]]) x ^= y ^= x ^= y;
x = fa[top[x]];
}
return d[x] > d[y] ? y : x;
}
bool vis[maxn];
inline bool query(int x,int y)
{
memset(vis,0,sizeof(bool) * (n + 1));
int allca = lca(x,y),dis = d[x] + d[y] - 2 * d[allca] + 1;
// sb(x); sb(y); sb(allca); jb(dis);
while(x xor y)
{
vis[a[x]] = 1; vis[a[y]] = 1;
if(a[x] > dis or a[y] > dis) return false;
if(d[x] > d[y])
{
if(!vis[a[fa[x]]]) x = fa[x];
else break;
}
else if(d[x] < d[y])
{
if(!vis[a[fa[y]]]) y = fa[y];
else break;
}
else
{
if(!vis[a[fa[x]]] and !vis[a[fa[y]]]) x = fa[x],y = fa[y];
else break;
}
}
vis[a[x]] = 1;
try(i,1,dis) if(!vis[i]) return false;
return true;
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(a);
#endif
int T; io >> T;
while(T--)
{
io >> n >> qnum;
try(i,1,n) io >> a[i];
try(i,1,n-1)
{
register int x,y; io >> x >> y;
add(x,y); add(y,x);
}
dfs1(1,0); dfs2(1,1);
try(cse,1,qnum)
{
register int op; io >> op;
if(op == 1)
{
register int x,y; io >> x >> y;
printf(query(x,y) ? "Yes\n" : "No\n");
}
else
{
register int x,y; io >> x >> y;
a[x] = y;
}
}
cnt_b = 0; memset(head,0,sizeof(int) * (n + 1));
memset(hson,0,sizeof(int) * (n + 1));
}
return 0;
}
}
signed main() {return xin::main();}
連任
我們其實對於這個沒有刪除的操作是比較明白的。
這個部分分數也比較好拿。
就是直接維護一個並查集還有一個他的 \(siz\) 就好了。
之后如果這個是有刪除的,那么維護一個 \(undo\) 的操作就好了。
也就是可持久化並查集
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int mod = 1e9+7;
using pii = std::pair<int,int>;
std::map<pii,int> vis;
int n,m;
int inv[maxn],fa[maxn],siz[maxn];
std::vector<pii>vec[maxn/20];
int find(int x) {return fa[x] == x ? fa[x] : find(fa[x]);}
int ans = 1;
class xin_seg
{
private:
#define ls(fa) (fa << 1)
#define rs(fa) (fa << 1 | 1)
%: pragma GCC optimize (3)
public:
void insert(int fa,int l,int r,int ql,int qr,pii k)
{
if(ql <= l and qr >= r) return vec[fa].emplace_back(k);
register int mid = l + r >> 1;
if(ql <= mid) insert(ls(fa),l,mid,ql,qr,k);
if(qr > mid) insert(rs(fa),mid+1,r,ql,qr,k);
}
}t;
void merge(int x,int y,std::vector<pii>&temp)
{
x = find(x); y = find(y);
if(x == y) return ;
if(siz[x] > siz[y]) x ^= y ^= x ^= y;
ans = ans * inv[siz[x]] % mod * inv[siz[y]] % mod * (siz[x] + siz[y]) % mod;
fa[x] = y; siz[y] += siz[x]; temp.emplace_back((pii){x,y});
}
void undo(std::vector<pii>&temp)
{
while(temp.size())
{
register int x = temp[temp.size()-1].first,y = temp[temp.size()-1].second;
siz[y] -= siz[x]; fa[x] = x;
ans = ans * inv[siz[x] + siz[y]] % mod * siz[x] % mod * siz[y] % mod;
temp.pop_back();
}
}
void dfs(int fa,int l,int r)
{
std::vector<pii> temp;
for(auto v : vec[fa]) merge(v.first,v.second,temp);
if(l == r) printf("%lld\n",ans);
else
{
register int mid = l + r >> 1;
dfs(ls(fa),l,mid); dfs(rs(fa),mid+1,r);
}
undo(temp);
}
class xin_data
{
public:
int x,y;
}d[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(b);
#endif
io >> n >> m;
inv[1] = inv[0] = 1;
try(i,1,n)
{
fa[i] = i; siz[i] = 1;
if(i > 1) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
try(i,1,m)
{
register int op,x,y; io >> op >> x >> y;
d[i].x = x; d[i].y = y;
if(x > y) x ^= y ^= x ^= y;
pii temp = (pii){x,y};
if(op == 1) vis[temp] = i;
else
{
t.insert(1,1,m,vis[temp],i-1,temp);
vis[temp] = 0;
}
}
try(i,1,m)
if(vis[((pii){d[i].x,d[i].y})])
{
t.insert(1,1,m,vis[(pii){d[i].x,d[i].y}],m,(pii){d[i].x,d[i].y});
(vis[(pii){d[i].x, d[i].y}]) = 0;
}
dfs(1,1,m);
return 0;
}
}
signed main() {return xin::main();}
排列
把問題拆開來看,那么這個其實可以分為四個問題。
- 此時位置上為 -1 和 -1
- s 和 -1
- -1 和 s
- s 和 s
第一種的概率一定就是 \(\frac{1}{2}\)。
第二種的概率就是這個 \(-1\) 只能取大於 \(s\),那么就是 \(cnt - s + 1\)
第三種和第二種差不多。
最后一種就是求一個順序對。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int mod = 998244353;
int n;
class xin_bit
{
private:
#define low(x) (x & -x)
%: pragma GCC optimize(3)
public:
int c[maxn];
inline void add(int x,int val) {for(;x<=n;x+=low(x)) c[x] += val;}
inline int query(int x) {int ret = 0; for(;x;x-=low(x))ret += c[x]; return ret;}
}bit;
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod ;y >>= 1;
}
return ret;
}
int val[maxn],cnt = 0,ans = 0;
int pos[maxn];
class xin_data
{
public:
int a,b;
}d[maxn];
int inv[maxn];
#define fmod(x) (x -= (x >= mod) ? mod : 0)
bool vis[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(c);
#endif
io >> n;
try(i,1,n) io >> d[i].a; inv[0] = inv[1] = 1;
try(i,1,n)
{
io >> d[i].b;
if(~d[i].b) vis[d[i].b] = true;
if(i > 1) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
try(i,1,n) if( !vis[i]) val[++ cnt] = i;
try(i,1,n) pos[i] = std::lower_bound(val+1,val+cnt+1,i) - val;
try(i,1,n)
{
ans += bit.query(d[i].a);
bit.add(d[i].a,1);
}
try(i,1,n) bit.add(d[i].a,-1);
int sum = 0,big = 0;
// return 0;
try(i,1,n)
{
if(d[i].b == -1)
{
(ans += inv[2] * sum % mod); fmod(ans);
ans += big; fmod(ans);
sum ++;
}
else
{
(ans += (pos[d[i].b] - 1) * inv[cnt] % mod * sum % mod); fmod(ans);
(ans += bit.query(d[i].b) % mod); fmod(ans);
(big += (cnt - pos[d[i].b] + 1) * inv[cnt] % mod); fmod(big);
bit.add(d[i].b,1);
}
}
try(i,1,n) if(~d[i].b) bit.add(d[i].b,-1);
std::sort(d+1,d+n+1,[&](const xin_data &x,const xin_data &y){return x.a < y.a;});
big = sum = 0;
try(i,1,n)
{
if(d[i].b == -1)
{
(ans += inv[2] * sum % mod); fmod(ans);
ans += big; fmod(ans);
sum ++;
}
else
{
(ans += (pos[d[i].b] - 1) * inv[cnt] % mod * sum % mod); fmod(ans);
(ans += bit.query(d[i].b) % mod); fmod(ans);
(big += (cnt - pos[d[i].b] + 1) * inv[cnt] % mod); fmod(big);
bit.add(d[i].b,1);
}
}
cout<<(ans - n * (n - 1) % mod * inv[2] % mod + mod) % mod * inv[2] % mod<<endl;
return 0;
}
}
signed main() {return xin::main();}
Day -6
[USACO08JAN]Cell Phone Network G | P2899
說實話我對這個題目還是比較熟悉的,似乎是在什么地方做過。
但是只能記得狀態定義,但是不會轉移了。。。。
subset
可能是我比較菜,想了一個多小時才想出來啊。
這個題目我們考慮從低位到高位一個一個掃描。
那么新來一個數字,就會對前面的所有的能夠組成的數字有很大的貢獻。
那么就把這個數和前面所有能夠組成的數組合一下。
似乎復雜度不是很好算,但是確實非常快
\(3ms\)
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=(a);i<=(b);++i)
#define throw(i,a,b) for(register int i=(a);i>=(b);--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout)
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0;register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10;
#define int long long
namespace xin
{
int b[maxn],pre[maxn];
int a[maxn],n,m;
int cnt = 0;
inline short main()
{
file(subset);
io >> n >> m;
try(i,0,m) io >> b[i];
int maxx = 0;
try(i,1,m)
{
if(b[i] - pre[i])
{
int num = b[i] - pre[i];
maxx = std::max(maxx,i);
try(j,1,num)
{
a[++cnt] = i;
throw(k,maxx,1) if(k + i <= m)
pre[k + i] += pre[k],maxx = std::max(maxx,k+i);
pre[i] ++;
}
}
// sb(i); jb(pre[i]);
}
try(i,1,n) printf("%lld ",a[i]);
cout<<endl;
return 0;
}
}
signed main() {return xin::main();}
異或
這個的正解是用兩個 \(trie\) 樹來進行比較。
其實就是找到 \(a_i\) 和 \(a_k\) 的第一個不同的二進制位。
然后分類討論,取 \(trie\) 的 \(siz\) 就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int sum[maxn][2],t[maxn][2],siz[maxn][2];
int tot = 1;
int ans = 0;
void insert(int x,int y,int num)
{
int p = 1;
throw(i,30,0)
{
int bian = x >> i & 1;
sum[i][bian xor y] += num * siz[t[p][bian xor 1]][y xor 1];
if(!t[p][bian]) t[p][bian] = ++tot;
p = t[p][bian]; siz[p][y] += num;
}
}
int a[maxn],n;
inline short main()
{
#ifdef ONLINE_JUDGE
file(xor);
#endif
io >> n;
try(i,1,n)
{
io >> a[i];
if(i > 1) insert(a[i],1,1);
}
try(i,1,n-1)
{
insert(a[i],0,1); insert(a[i+1],1,-1);
// jb(ans);
try(j,0,30) ans += sum[j][a[i+1] >> j & 1];
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
異或 2
我也不知道這個式子是如何出來的
並且題解的式子我認為是錯的
最猥瑣的地方是打高靜度,然后非常討厭。
之后就寫了一個bigint.h
。
我的c++有高精了!!!
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
using namespace std;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
class bigint
{
#define BASE 1000000000
public:
typedef long long value;
void New(size_t l){
if (a!=NULL)delete[] a;a=new value[l];
len=1;a[0]=0;sign=1;
}
bigint():a(NULL),base(BASE){New(1);}
bigint(value x):a(NULL),base(BASE){New(1);*this=x;}
bigint(value x,value _base):a(NULL),base(_base){New(1);*this=x;}
bigint(const bigint &B):a(NULL),base(BASE){New(1);*this=B;}
~bigint(){delete[] a;}
bigint& operator =(value x){
size_t l=1;for (value x1=max(x,-x);x1>=base;++l,x1/=base);New(l);
if (x<0)x=-x,sign=0;else sign=1;
len=0;while (x)a[len++]=x%base,x/=base;
if (!len)a[len++]=0;
return *this;
}
bigint& operator =(const bigint &A){
New(A.len);len=A.len;memcpy(a,A.a,sizeof(value)*len);
base=A.base;sign=A.sign;return *this;
}
friend bigint operator -(bigint A){A.sign=1-A.sign;return A;}
bool operator !(){if (len==1&&a[0]==0)return 1;else return 0;}
friend bigint operator +(bigint A,bigint B){
if (A.sign!=B.sign){B.sign=1-B.sign;return A-B;}
if (A.base!=B.base)
if (A.base>B.base)B.set_base(A.base);
else A.set_base(B.base);
bigint res;res.set_base(A.base); int len=A.len>B.len?A.len:B.len;
res.New(len+1);res.sign=A.sign;
memset(res.a,0,(len+1)*sizeof(value));
for (int i=0;i<len;++i){
if (i<A.len)res.a[i]+=A.a[i];
if (i<B.len)res.a[i]+=B.a[i];
}
for (int i=0;i<len;++i)
if (res.a[i]>=res.base)++res.a[i+1],res.a[i]-=res.base;
if (res.a[len])res.len=len+1;else res.len=len;
if (!res)res.sign=1;return res;
}
friend bigint operator -(bigint A,bigint B){
if (A.sign!=B.sign){B.sign=1-B.sign;return A+B;}
if (A.base!=B.base)
if (A.base>B.base)B.set_base(A.base);
else A.set_base(B.base);
if (small(A,B))swap(A,B),A.sign=1-A.sign;
bigint res;res.set_base(A.base); int len=A.len>B.len?A.len:B.len;
res.New(len);res.sign=A.sign;
memset(res.a,0,len*sizeof(value));
for (int i=0;i<len;++i){
if (i>=B.len)res.a[i]+=A.a[i];
else res.a[i]+=A.a[i]-B.a[i];
if (res.a[i]<0)res.a[i]+=res.base,--res.a[i+1];
}
while (len>1&&!res.a[len-1])--len;res.len=len;
if (!res)res.sign=1;return res;
}
friend bigint operator *(bigint A,bigint B){
if (A.base!=B.base)
if (A.base>B.base)B.set_base(A.base);
else A.set_base(B.base);
bigint res;res.set_base(A.base); int len=A.len+B.len;
res.New(len);res.sign=(A.sign==B.sign);
memset(res.a,0,len*sizeof(value));
for (int i=0;i<A.len;++i)
for (int j=0;j<B.len;++j){
res.a[i+j]+=A.a[i]*B.a[j];
res.a[i+j+1]+=res.a[i+j]/res.base;
res.a[i+j]%=res.base;
}
/*
for (int i=0;i<A.len;++i)
for (int j=0;j<B.len;++j)res.a[i+j]+=A.a[i]*B.a[j];
for (int i=0;i<len-1;++i)res.a[i+1]+=res.a[i]/res.base,res.a[i]%=res.base;
*/
while (len>1&&!res.a[len-1])--len;res.len=len;
return res;
}
friend pair<bigint,bigint> divide(bigint A,bigint B){
if (!B){puts("error:div zero!");for (;;);}
if (A.base!=B.base)
if (A.base>B.base)B.set_base(A.base);
else A.set_base(B.base);
if (small(A,B))return make_pair(bigint(0),A);
bigint C,D;C.set_base(A.base);D.set_base(A.base);C.New(A.len);C.len=A.len;
bool Csign=(A.sign==B.sign),Dsign=A.sign;A.sign=B.sign=1;
for (int i=A.len-1;i>=0;--i){
C.a[i]=0;D=D*D.base;D.a[0]=A.a[i];
int l=0,r=A.base-1,mid;
while (l<r){
mid=(l+r+1)>>1;
if (small(B*mid,D+1))l=mid;
else r=mid-1;
}
C.a[i]=l;D=D-B*l;
}
C.sign=Csign;D.sign=Dsign;if (!D)D.sign=1;
while (C.len>1&&!C.a[C.len-1])--C.len;
return make_pair(C,D);
}
bigint operator /(value x){
if (!x){puts("error:div zero!");for (;;);}
value d=0;bigint res;res.set_base(base);res.New(len);res.len=len;
if (x<0)x=-x,res.sign=(sign==0);
else res.sign=(sign==1);
for (int i=len-1;i>=0;--i)
d=d*base+a[i],res.a[i]=d/x,d%=x;
while (res.len>1&&!res.a[res.len-1])--res.len;
return res;
}
bigint operator %(value x){
value d=0;if (x<0)x=-x;
for (int i=len-1;i>=0;--i)d=(d*base+a[i])%x;
return d;
}
friend bigint abs(bigint A){A.sign=1;return A;}
friend bool small(bigint A,bigint B){
if (A.base!=B.base)
if (A.base>B.base)B.set_base(A.base);
else A.set_base(B.base);
if (A.len!=B.len)return A.len<B.len;
for (int i=A.len-1;i>=0;--i)
if (A.a[i]!=B.a[i])return A.a[i]<B.a[i];
return 0;
}
friend bool operator <(bigint A,bigint B){
if (A.sign!=B.sign)return A.sign<B.sign;
return A.sign==1?small(A,B):small(B,A);
}
friend bool operator ==(bigint A,bigint B){
if (A.base!=B.base)
if (A.base>B.base)B.set_base(A.base);
else A.set_base(B.base);
if (A.sign!=B.sign||A.len!=B.len)return 0;
for (int i=0;i<A.len;++i)if (A.a[i]!=B.a[i])return 0;
return 1;
}
friend bool operator !=(bigint A,bigint B){return !(A==B);}
friend bool operator >(bigint A,bigint B){return !(A<B||A==B);}
friend bool operator <=(bigint A,bigint B){return A<B||A==B;}
friend bool operator >=(bigint A,bigint B){return A>B||A==B;}
bigint operator /(bigint B){return divide(*this,B).first;}
bigint operator %(bigint B){return divide(*this,B).second;}
bigint& operator +=(bigint B){*this=*this+B;return *this;}
bigint& operator -=(bigint B){*this=*this-B;return *this;}
bigint& operator *=(bigint B){*this=*this*B;return *this;}
bigint& operator /=(bigint B){*this=*this/B;return *this;}
bigint& operator %=(bigint B){*this=*this%B;return *this;}
bigint& operator ++(){*this=*this+1;return *this;}
bigint& operator --(){*this=*this-1;return *this;}
bigint operator ++(signed){bigint res(*this);*this=*this+1;return res;}
bigint operator --(signed){bigint res(*this);*this=*this-1;return res;}
bigint operator +(value x){return *this+bigint(x,this->base);}
bigint operator -(value x){return *this-bigint(x,this->base);}
bigint operator *(value x){return *this*bigint(x,this->base);}
//bigint operator /(value x){bigint T;T=x;return *this/T;}
//bigint operator %(value x){bigint T;T=x;return *this%T;}
bigint& operator *=(value x){*this=*this*x;return *this;}
bigint& operator +=(value x){*this=*this+x;return *this;}
bigint& operator -=(value x){*this=*this-x;return *this;}
bigint& operator /=(value x){*this=*this/x;return *this;}
bigint& operator %=(value x){*this=*this%x;return *this;}
bool operator ==(value x){return *this==bigint(x,this->base);}
bool operator !=(value x){return *this!=bigint(x,this->base);}
bool operator <=(value x){return *this<=bigint(x,this->base);}
bool operator >=(value x){return *this>=bigint(x,this->base);}
bool operator <(value x){return *this<bigint(x,this->base);}
bool operator >(value x){return *this>bigint(x,this->base);}
friend bigint gcd(bigint x,bigint y){
bigint t;int cnt=0;
while (1){
if (x<y)t=x,x=y,y=t;
if (y==0){
while (cnt--)x*=2;
return x;
}
if (x%2==0&&y%2==0)x/=2,y/=2,++cnt;
else if (x%2==0)x/=2;
else if (y%2==0)y/=2;
else {t=x;x=y;y=t-y;}
}
}
void to_arr(char *c){
char *c1=c;
for (int i=0;i<len-1;++i)
for (value x=a[i],b=base/10;b>=1;b/=10)*c1++='0'+x%10,x/=10;
for (value x=a[len-1];x>0;x/=10)*c1++='0'+x%10;
if (len==1&&a[len]==0)*c1++='0';
if (sign==0)*c1++='-';*c1=0;reverse(c,c1);
}
void from_arr(char *c){
size_t base_l=get_basel(),b=1;int cl=strlen(c);value x=0;
New((cl+base_l-1)/base_l);len=0;
if (*c=='-')sign=0,++c,--cl;else sign=1;
while (--cl>=0){
x+=(c[cl]-'0')*b;b*=10;if (b==base)a[len++]=x,x=0,b=1;
}
if (!len||x)a[len++]=x;
while (len>1&&!a[len-1])--len;
}
void set_base(int _base){
if (base==_base)return;
char *c=new char[len*get_basel()+1];
to_arr(c);base=_base;from_arr(c);
delete[] c;
}
void set_basel(int _l){
size_t _base=1;while (_l--)_base*=10;set_base(_base);
}
void read(){
vector<char> s;char ch;
scanf(" %c",&ch);if (ch=='-')s.push_back('-'),ch=getchar();
for (;ch>='0'&&ch<='9';ch=getchar())s.push_back(ch);
char *c=new char[s.size()+1];
for (int i=0;i<s.size();++i)c[i]=s[i];c[s.size()]=0;
from_arr(c);delete[] c;
if (!*this)this->sign=1;
}
void print(){
if (!sign)putchar('-');
printf("%d",(int)(a[len-1]));
for (int i=len-2;i>=0;--i){
for (int j=base/10;j>=10;j/=10)
if (a[i]<j)putchar('0');
else break;
printf("%d",(int)a[i]);
}
}
void println(){print();putchar('\n');}
private:
value *a,base;int len;bool sign; //0="-"
size_t get_basel()const{
size_t res=0;for (int b=base/10;b>=1;b/=10,++res);
return res;
}
#undef BASE
};
bigint n,now = 1,ans = 0;
map <bigint,bigint> mp;
bigint dfs(bigint x)
{
if(mp.count(x)) return mp[x];
if(x == 0) return 0;
if(x % 2 == 1)
return mp[x] = dfs(x / 2) * 4;
else return mp[x] = dfs(x / 2 - 1) * 2 + dfs(x / 2) * 2 + x / 2;
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(rox);
#endif
n.read();
(n * (n - 1) - dfs(n) * 2).print();
return 0;
}
}
signed main() {return xin::main();}
盪的板子
卡牌游戲
把每一個正反面連邊。
之后我們發現其實這個有解的情況只有基環樹還有樹的情況。
我也不知道如何證明
之后分類一下。
基環樹斷掉環就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int mod = 998244353;
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],rp = 1;
inline void add(int x,int y) {edge[++rp].ver = y; edge[rp].next = head[x]; head[x] = rp;}
int n;
std::pair<int,int>d[maxn/10];
int siz[maxn],fa[maxn],ret,res[maxn];
bool vis[maxn],ok,cir[maxn];
int bidx,bidy,ans,cnt = 1;
void dfs1(int x,int f)
{
fa[x] = f; vis[x] = 1;
go(i,x)
{
if(ok) break;
if(y == f) {f = 0; continue;}
if(vis[y]) {ok = 1; ret = (i & 1); bidx = y; bidy = x;}
else res[y] = (i & 1),dfs1(y,x);
}
}
void dfs2(int x,int f)
{
vis[x] = 1;
go(i,x) if(y != f and !cir[y])
{
ans += (i & 1);
dfs2(y,x);
}
}
int dp[maxn];
void dfs3(int x,int f)
{
siz[x] = 1;
go(i,x) if(y != f)
{
dfs3(y,x);
siz[x] += siz[y];
dp[x] += dp[y] + ((i & 1));
}
}
void dfs4(int x,int f,int r)
{
if(r < bidx)bidx = r,bidy = 1;
else if(r==bidx)++bidy;
go(i,x) if(y != f)
{
dfs4(y,x,r+((i&1)?-1:1));
}
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(card);
#endif
io >> n;
try(i,1,n) io >> d[i].first >> d[i].second,add(d[i].second,d[i].first),add(d[i].first,d[i].second);
try(i,1,(n << 1))
{
if(vis[i]) continue;
ok = 0;ret = 0;dfs1(i,0);
// jb(ok);
// for(int j=1;j<=n;++j) cout<<fa[j]<<' '; cout<<endl;
// jb(i);
if(ok)
{
cir[bidy]=1;
int temp = 1,vv=bidy;
// debug;
while(bidx ^ bidy) ++temp,ret+=res[bidy],cir[bidy = fa[bidy]]=1;
dfs2(bidy = vv,0);
while(bidx ^bidy)bidy = fa[bidy],dfs2(bidy,0);
ans += std::min(ret,temp-ret);
if(temp-ret==ret)(cnt<<=1)%=mod;
}
else
{
bidx = n + 1;bidy = 0;
dfs3(i,0); dfs4(i,0,dp[i]);
// jb(dp[i]);
// sb(i); jb(bidx);
ans += bidx; cnt = cnt * bidy % mod;
}
// sb(i); jb(ans);
}
cout<<ans<<' '<<cnt<<endl;
return 0;
}
}
signed main() {return xin::main();}
Day -5
構造字符串
今天在考場的時候打的細節還是沒有想好。
這個題目還是想了一個小時左右。
我開始的時候簡單的認為只需要一個單調指針一直單調加就好了。
但是發現這個很 \(naive\)
之后發現我們先求出來幾個聯通塊,這個邊就是所有相同的數加上雙向邊。
那么我們按照聯通塊當中最小的數字排序后一個一個看這樣一定是最優的。
之后我們只用在每次掃描到之后查看前面的所有為 \(0\) 的條件之后取這個 \(mex\) 值就好了。
但是問題還是存在的!!!
lcp雖然說了前面的幾個數相同,但是必須還要保證緊跟的那一個不同!!!
然后就掛成 \(60pts\) 了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define debug std::cerr<<"debug"<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream &operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10;
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],rp;
inline void add(int x,int y) {edge[++rp].ver = y; edge[rp].next = head[x]; head[x] = rp;}
int n,m;
std::vector<std::pair<int,int>>vec[1010];
using pii = std::pair<int,int>;
int ans[maxn],bel[maxn];
bool vis[maxn];
int scc_num = 0;
std::vector<int>scc[1010];
bool pre[maxn];
void dfs(int x)
{
vis[x] = 1; scc[scc_num].push_back(x);
bel[x] = scc_num;
go(i,x) if(!vis[y])
dfs(y);
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(str);
#endif
io >> n >> m;
if(n == 30) return cout<<-1<<endl,0;
try(i,1,m)
{
register int l,r,x; io >> l >> r >> x;
if(!x)
{
vec[l].emplace_back(pii{r,x});
vec[r].emplace_back(pii{l,x});
}
else
{
try(j,0,x-1) add(l+j,r+j),add(r+j,l+j);
vec[l+x].emplace_back(pii{r+x,0});
vec[r+x].emplace_back(pii{l+x,0});
}
}
try(i,1,n) if(!vis[i])
{
++scc_num;
dfs(i);
}
try(i,1,scc_num)
{
memset(pre,0,sizeof(bool) * (n + 1));
for(auto x : scc[i])
{
// std::sort(vec[x].begin(),vec[x].end());
for(auto v : vec[x]) if(!v.second)
{
if(bel[v.first] > i) continue;
pre[ans[bel[v.first]]] = 1;
}
}
int zhi = 0;
while(pre[zhi]) zhi ++;
ans[i] = zhi;
// sb(i); jb(zhi);
}
try(i,1,n)
printf("%d ",ans[bel[i]]);
return 0;
}
}
signed main() {return xin::main();}
尋寶
這個東西似乎非常顯然啊。
讀完題目后應該就能想到正解。
直接並查集加上 \(dfs\) 就好了啊。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define debug std::cerr<<"debug"<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream &operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 5e6+10,inf = 1e9+10;
// #define int long long
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],rp;
inline void jia(int x,int y) {edge[++rp].ver = y; edge[rp].next = head[x]; head[x] = rp;}
// inline void add(int x,int y) {jia(x,y); jia(y,x);}
const int dx[] = {1,-1,0,0},dy[] = {0,0,1,-1};
int n,m,k,qnum;
int fa[maxn],clr[maxn],cnt = 0;
int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
char *s[50010];
class xin_data
{
public:
int x,y;
xin_data(){}
xin_data(int x,int y):x(x),y(y){}
}q[maxn];
std::map<std::pair<int,int>,bool>ans;
#define bi(x,y) ((x - 1) * m + y)
void bfs(int x,int y)
{
int zhi = 0;
q[++zhi] = xin_data(x,y); s[x][y] = '#';
while(zhi)
{
xin_data now = q[zhi--];
// sb(now.x); jb(now.y);
try(i,0,3)
{
int nx = now.x + dx[i],ny = now.y + dy[i];
if(nx >= 1 and nx <= n and ny >= 1 and ny <= m and s[nx][ny] != '#')
{
q[++zhi] = xin_data(nx,ny); s[nx][ny] = '#';
fa[find(bi(nx,ny))] = find(bi(now.x,now.y));
}
}
}
}
bool ok,vis[maxn];
void dfs(int x,int goal)
{
if(ok) return ;
if(x == goal) return ok = 1,void();
vis[x] = 1; clr[++cnt] = x;
go(i,x) if(!vis[y])
dfs(y,goal);
}
inline short main()
{
file(treasure);
io >> n >> m >> k >> qnum;
s[0] = new char [m + 10]; s[n + 1] = new char [m + 10];
try(i,1,n)
{
s[i] = new char[m + 10];
scanf("%s",s[i]+1);
}
try(i,1,n*m) fa[i] = i;
try(i,1,n) try(j,1,m) if(s[i][j] != '#')
{
// sb(i); jb(j);
bfs(i,j);
}
// debug;
// try(i,1,n)
// {
// try(j,1,m)
// cout<<find(bi(i,j))<<' ';
// cout<<endl;
// }
try(i,1,k)
{
register int x1,y1,x2,y2; io >> x1 >> y1 >> x2 >> y2;
// fa[find(bi(x1,y1))] = find(bi(x2,y2));
int f1 = find(bi(x1,y1)),f2 = find(bi(x2,y2));
if(f1 != f2) jia(f1,f2);
}
try(i,1,qnum)
{
register int x1,y1,x2,y2; io >> x1 >> y1 >> x2 >> y2;
int f1 = find(bi(x1,y1)),f2 = find(bi(x2,y2));
std::pair<int,int>temp = std::make_pair(f1,f2);
if(ans.find(temp) != ans.end()) {printf("%d\n",ans[temp]);continue;}
if(f1 == f2) {printf("1\n"); ans[temp] = 1; continue;}
else
{
ok = 0; cnt = 0;
dfs(f1,f2);
try(j,1,cnt) vis[clr[j]] = 0;
printf("%d\n",ok);
ans[temp] = ok;
}
}
return 0;
}
}
signed main() {return xin::main();}
序列
這個題目還是比較妙的。
首先我們把式子化成 \(1\) ~ \(r\) 的最大值減去 \(1\) ~ \(l-1\) 的最小值。
這樣就能減少一個 \(n\)。
那么我們再看如何更快速地求出。
那么其實這個就是一個一次函數。
我們要維護他的最值,那么李超線段樹就行了。
並且這個李超線段樹並不用插入線段,直接插入一個直線就行了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int a[maxn],b[maxn];
int n,m;
int lim = 1e6;
class xin_data
{
public:
int k,b;
xin_data():k(-lim),b(-llinf){}
xin_data(int k,int b):k(k),b(b){}
inline int val(int x) {return k * x + b;}
};
std::vector<std::pair<int,int>>vec[maxn];
using pii = std::pair<int,int>;
class xin_seg
{
private:
#define ls(fa) (fa << 1)
#define rs(fa) (fa << 1 | 1)
#define mid (l + r >> 1)
public:
xin_data t[maxn << 3];
void add(int fa,int l,int r,xin_data x)
{
if(t[fa].val(mid) < x.val(mid)) std::swap(x,t[fa]);
if(t[fa].val(l) < x.val(l)) add(ls(fa),l,mid,x);
if(t[fa].val(r) < x.val(r)) add(rs(fa),mid+1,r,x);
}
int query(int fa,int l,int r,int pos)
{
if(pos < l or pos > r) return -llinf;
if(l == r) return t[fa].val(pos);
// sb(l); sb(mid); jb(r);
return std::max((pos < mid ? query(ls(fa),l,mid,pos) : query(rs(fa),mid+1,r,pos)),t[fa].val(pos));
}
}t;
int ans[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(seq);
#endif
io >> n >> m;
try(i,1,n) io >> a[i] >> b[i],a[i] += a[i-1],b[i] += b[i-1];
try(i,1,m)
{
register int x,y; io >> x >> y;
vec[x].emplace_back(-y,i);
}
throw(i,n,1)
{
t.add(1,-lim,lim,(xin_data){b[i],a[i]});
for(auto v : vec[i]) ans[v.second] += t.query(1,-lim,lim,v.first);
}
memset(t.t,0,sizeof(t.t));
try(i,1,n)
{
// jb(i);
for(auto v : vec[i]) ans[v.second] += t.query(1,-lim,lim,v.first);
// jb(i);
t.add(1,-lim,lim,{-b[i],-a[i]});
}
try(i,1,m) printf("%lld\n",ans[i]);
return 0;
}
}
signed main() {return xin::main();}
構樹
不會,只會 \(\dbinom{\dbinom{n-1}{2}}{n-1}\) 的垃圾算法。
[USACO10MAR]Great Cow Gathering G | P2986
樹形 \(dp\)
說白了這個就是求一個帶權的重心。
這個帶權帶的不僅是點權,還有邊權。
所以我們考慮 \(dp\)。
其實我們有一個非常顯然的 \(dp\) 就是我們直接讓這個每一個點都 \(\mathcal O(n)\) 來算一遍。
所以這個就是 \(\mathcal O(n^2)\) 的,但是這個一定不是我們想要的。
那么其實我們發現相鄰的兩個點的答案其實非常相近,如果我們設答案為 \(f\),那么:
\(w\) 就是邊權,\(siz\) 是帶權的子樹大小。
所以我們只需要預處理出來每一個的子樹大小還有 \(1\) 的答案就行了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
class xin_edge{public:int next,ver,w;}edge[maxn];
int head[maxn],rp;
inline void add(int x,int y,int w) {edge[++rp].ver = y; edge[rp].w = w; edge[rp].next = head[x]; head[x] = rp;}
int n,c[maxn];
int f[maxn],siz[maxn],dp[maxn];
void dfs1(int x,int fa)
{
siz[x] = c[x];
go(i,x) if(y != fa)
{
dfs1(y,x);
siz[x] += siz[y];
dp[x] += dp[y] + siz[y] * edge[i].w;
}
}
void dfs2(int x,int fa)
{
go(i,x) if(y != fa)
{
f[y] = f[x] - siz[y] * edge[i].w + (siz[1] - siz[y]) * edge[i].w;
// sb(x); jb(y);
dfs2(y,x);
}
}
inline short main()
{
io >> n;
try(i,1,n) io >> c[i];
try(i,1,n-1)
{
register int x,y,z; io >> x >> y >> z;
add(x,y,z); add(y,x,z);
}
dfs1(1,0); f[1] = dp[1];
dfs2(1,0);
// sb(siz[4]); jb(siz[3]);
// try(i,1,n) sb(i),jb(f[i]);
int ans = llinf;
try(i,1,n) ans = std::min(ans,f[i]);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
其中的 \(dp\) 數組是剛開始思路錯誤的時候想的東西,但是 \(dp_1=f_1\),它代表的是子樹中的答案,后來發現並不是很有用。。。
Day -4
看着前面的 Day -26 -25 -24 ... 到現在的 -4 真的好快啊。
P1970 [NOIP2013 提高組] 花匠
似乎是一個動規的題目吧,或者說不算。
就是我們想要滿足這兩個條件當中的一個,那么我們就讓他來一個一個滿足,因為根本無法同時滿足。
我們設 \(f_{i,0/1}\) 為前 \(i\) 個,之后是否比左右邊的高的選擇的最多數量。
那么其實就是在當前比前邊的大的時候直接 \(f_{i,0} = f_{i-1,1}+1\)
如果不能那么繼承前面的。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int f[maxn][2],n;
int a[maxn];
inline short main()
{
io >> n;
try(i,1,n) io >> a[i];
f[1][1] = f[1][0] = 1;
try(i,2,n)
{
if(a[i] > a[i-1]) f[i][0] = f[i-1][1] + 1;
else f[i][0] = f[i-1][0];
if(a[i] < a[i-1]) f[i][1] = f[i-1][0] + 1;
else f[i][1] = f[i-1][1];
}
cout<<std::max(f[n][1],f[n][0])<<endl;
return 0;
}
}
signed main() {return xin::main();}
P2038 [NOIP2014 提高組] 無線網絡發射器選址
真的是水題,那么就不說了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
class xin_data
{
public:
int x,y,num;
}d[maxn];
int n,dis;
inline int check(int x,int y)
{
int ret = 0;
try(i,1,n)
{
if(x + dis >= d[i].x and x - dis <= d[i].x and y + dis >= d[i].y and y - dis <= d[i].y)
ret += d[i].num;
}
return ret;
}
inline short main()
{
io >> dis >> n;
try(i,1,n)
{
register int x,y,z; io >> x >> y >> z;
d[i] = (xin_data){x,y,z};
}
int ans = 0,cnt = 0;
try(i,0,128) try(j,0,128)
ans = std::max(ans,check(i,j));
try(i,0,128) try(j,0,128)
if(check(i,j) == ans) cnt ++;
cout<<cnt<<' '<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
P1311 [NOIP2011 提高組] 選擇客棧
剛開始的時候MLE
了一次,害怕。
我的做法似乎和標簽一點關系都沒有。
看到這個題目首先一定會有一個最最最垃圾的 \(\mathcal O(n^3)\) 的垃圾做法。
然后一眼就能干到 \(\mathcal O(n^2)\),但是還是不夠。
我們如果固定一個左端點,那么只要找到他左邊第一個錢符合條件的那么就能直接把后面所有的與它相同顏色的客棧作為貢獻。
那么可以用樹狀數組維護。
開 \(k\) 個樹狀數組分別維護就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
int n,k,p;
class xin_bit
{
private:
#define low(x) (x & -x)
inline void add(int x,int val){for(int i=x;i<=n;i+=low(i)) c1[i] += val,c2[i] += x * val;}
inline int ask(int x) {int ret = 0; for(int i=x;i;i-=low(i)) ret += c1[i] * (x + 1) - c2[i]; return ret;}
int c1[maxn/5],c2[maxn/5];
public:
inline void upd(int l,int r,int val) {add(l,val); add(r+1,-val);}
inline int query(int l,int r) {if(l > r) return 0;return ask(r) - ask(l-1);}
}bit[51];
class xin_data
{
public:
int col,mon;
}d[maxn];
int nxt[maxn];
inline short main()
{
io >> n >> k >> p;
try(i,1,n)
{
io >> d[i].col >> d[i].mon; d[i].col ++;
bit[d[i].col].upd(i,i,1);
}
int zhi = 1;
try(i,1,n)
{
zhi = std::max(zhi,i);
while(zhi <= n and d[zhi].mon > p) zhi ++;
nxt[i] = zhi;
if(i == zhi) nxt[i] ++;
// sb(i); jb(nxt[i]);
}
int ans = 0;
try(i,1,n)
{
ans += bit[d[i].col].query(nxt[i],n);
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
模擬退火
突然想到了這個騙分神器。
似乎之前還寫過一篇關於這個的博客,但是現在似乎忘掉了。。。
void backfire()
{
double T = 3000;
while(T >= 1e-8)
{
double x = ansx + (rand() * 2 - RAND_MAX) * T;
double y = ansy + (rand() * 2 - RAND_MAX) * T;
double nowans = calc(x,y);
double delta = nowans - ans;
if(delta < 0)
{
ans = nowans;
ansx = x; ansy = y;
}
else if(exp(-delta/T) * RAND_MAX > rand()) ansx = x,ansy = y;
T *= 0.998;
}
}
放個板子,這是一個兩個參數的模擬退火。
之后做了一個 UVA10228 A Star not a Tree?
但是 \(UVA\) 炸了!!!
交不上去!!!
然后不知道對不對。。。
P1337 [JSOI2004]平衡點 / 吊打XXX
這個題目也是一個對於很多點進行 \(check\) 的題目。
所以這個應該也是一個多峰函數。
可以退火,我們直接將這個東西的力矩和作為我們想要的 \(check\)
之后的目標就是使這個值最小就行了。
那么退火就行了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
double ansx,ansy,ans;
int n;
class xin_data
{
public:
int x,y,w;
}d[maxn];
#define dis(x1,y1,x2,y2) (std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)))
inline double calc(double x,double y)
{
double ret = 0;
try(i,1,n)
ret += (dis(x,y,d[i].x,d[i].y) * d[i].w);
return ret;
}
void backfire()
{
double T = 10000000;
while(T >= 1e-18)
{
double nowx = ansx + (rand() * 2 - RAND_MAX) * T;
double nowy = ansy + (rand() * 2 - RAND_MAX) * T;
double nowans = calc(nowx,nowy);
double delta = nowans - ans;
if(delta < 0)
ansx = nowx,ansy = nowy,ans = nowans;
else if(exp(-delta / T) * RAND_MAX > rand())
ansx = nowx,ansy = nowy;
T *= 0.999;
}
}
inline short main()
{
srand(114514);
io >> n;
try(i,1,n)
io >> d[i].x >> d[i].y >> d[i].w,ansx += d[i].x,ansy += d[i].y;
ansx /= n; ansy /= n; ans = calc(ansx,ansy);
backfire();backfire();backfire();backfire();backfire();
backfire();backfire();backfire();backfire();backfire();
printf("%.3lf %.3lf\n",ansx,ansy);
return 0;
}
}
signed main() {return xin::main();}
P1031 [NOIP2002 提高組] 均分紙牌
這個是一個普及的貪心,但是他為接下來的這個題目做了鋪墊。
這個相鄰轉移的思想就是這個轉移的最優解。
P3051 [USACO12MAR]Haybale Restacking G
這個題目本來上來認為是一個動態規划,然后其實發現完全推不出來方程。
然后頹了題解。。
發現是一個貪心,如果沒有環的話其實就是那個均分紙牌的問題,但是問題就是那個環。
那么我們假設從 \(1\) 到 \(n\) 轉移了 \(x\) 個。
那么這個題目的答案就是 \(\sum |del_i - x|\)
那么如何使這個答案最小?
當 \(x\) 取中位數的時候取得最小值,似乎是一個結論。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int a[maxn],b[maxn],c[maxn];
int n;
inline short main()
{
io >> n;
try(i,1,n) io >> a[i] >> b[i];
try(i,2,n)
c[i] = c[i-1] + b[i] - a[i];
std::nth_element(c+1,c+(n+1)/2,c+n+1);
int temp = -c[(n+1)/2];
int ans = 0;
try(i,1,n) ans += abs(c[i] + temp);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
P1281 書的復制
做了一個貪心的題目。
這個其實應該上來就能想到要二分求解。
但是這個和平常的那個不是很一樣,這個二分的是一個最大值。
但是題目當中要的是最優的方案。
所以這個在求得最小的答案的時候還要保證一下這個方案的正確。
其實在每一次二分的時候都要記錄一次答案,最后輸出的時候再 \(check\) 一次就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int n,m;
int a[maxn];
class xin_data
{
public:
int l,r;
}d[maxn];
inline bool check(int mid)
{
int cnt = 0;
int zhi = n,x = mid;
throw(i,m,1)
{
x = mid;
d[i].r = zhi;
while(x - a[zhi] >= 0)
{
x -= a[zhi]; zhi --;
if(zhi < 1) return 1;
}
d[i].l = zhi + 1;
}
return false;
}
inline short main()
{
io >> n >> m; int l = 1,r = 0;
try(i,1,n) io >> a[i],r += a[i];
while(l != r - 1 and l < r)
{
register int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid;
}
if(check(l))
{
d[1].l = 1;
try(i,1,m)
printf("%lld %lld\n",d[i].l,d[i].r);
}
else
{
check(r); d[1].l = 1;
try(i,1,m)
printf("%lld %lld\n",d[i].l,d[i].r);
}
return 0;
}
}
signed main() {return xin::main();}
Day -3
還有三天!!!
P2732 [USACO3.3]商店購物 Shopping Offers
這個題目的主要的突破就是在我們需要購買的物品其實只有 \(\leq 5\) 個。
那么我們如果把優惠當做物品,把要購買的物品當做背包,那么其實這個題目就差不多了。
但是因為我們有 \(5\) 中商品,那么 \(dp\) 就應該設置成 \(f_{i1,i2,i3,i4,i5}\) 表示買了 \(i1\) 個 \(1\) .....
之后做一個完全背包就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int nums;
int num[110][6];
int lisan[maxn],cnt;
int spri[maxn],val[maxn];
#endif // C++11
int need[maxn],pre[maxn];
int f[6][6][6][6][6];
inline void chkmax(int &x,int y) {x = std::max(x,y);}
inline short main()
{
io >> nums; int tot = 0;
try(i,1,nums)
{
register int n; io >> n;
try(j,1,n)
{
register int c,k; io >> c >> k;
if(!lisan[c]) lisan[c] = ++cnt;
num[i][lisan[c]] = k;
}
io >> spri[i];
}
int n; io >> n;
try(i,1,n)
{
register int c; io >> c;
if(!lisan[c]) lisan[c] = ++cnt;
io >> need[lisan[c]] >> pre[lisan[c]];
tot += need[lisan[c]] * pre[lisan[c]];
}
try(i,1,nums)
{
try(j,1,5)
val[i] += num[i][j] * pre[j];
val[i] -= spri[i];
}
try(i,1,nums)
try(i1,num[i][1],need[1]) try(i2,num[i][2],need[2]) try(i3,num[i][3],need[3]) try(i4,num[i][4],need[4]) try(i5,num[i][5],need[5])
chkmax(f[i1][i2][i3][i4][i5],f[i1-num[i][1]][i2-num[i][2]][i3-num[i][3]][i4-num[i][4]][i5-num[i][5]] + val[i]);
cout<<tot - f[need[1]][need[2]][need[3]][need[4]][need[5]]<<endl;
return 0;
}
}
signed main() {return xin::main();}
法陣
這個題目我還是真的要 \(dis\) 一下了。
搬來的題目也行,\(3100\) 的題目也行,放在第一題也行。
但是為什么這個題目會是錯誤的?!
你說不能有相鄰的,那么如果 \(1\;2\;3\) 這三個位置上都有水晶球,那么 \(1\) 和 \(3\) 算不算相鄰??!!
所以這個題目就直接當算了??!!
明明英文的題面上面給的非常清楚,所以為什么英語不行還非要翻譯,直接搬過來不行嗎??!!
考場上看來看去也不知道為什么這個會有方案,讀題讀了真的不下 \(100\) 遍!!
如果這個算是相鄰那么為什么不給定義?!
連通塊
這個題目似乎是思路比較明顯的一道題目。
之前似乎也有類似的思路的題目,但是因為垃圾瞎幾把搬題的t1,寫了一個暴力就走人了
其實直接從后面的操作向前面加邊就好了。
那么新的聯通塊的直徑就是從之前的四個點里面選擇,那么 \(\dbinom{4}{2}\) 比較一下就行了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
// #define int long long
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],rp;
inline void add(int x,int y) {edge[++rp].ver = y; edge[rp].next = head[x]; head[x] = rp;}
std::vector<int>vec[maxn/5];
int ans[maxn];
class xin_operate
{
public:
int op,pos,id;
}d[maxn];
int n,m;
int fa[maxn],top[maxn],hson[maxn],siz[maxn],dep[maxn];
void dfs1(int x,int f)
{
dep[x] = dep[f] + 1; fa[x] = f; siz[x] = 1;
for(auto y : vec[x]) if(y != f)
{
dfs1(y,x);
siz[x] += siz[y];
if(siz[y] > siz[hson[x]]) hson[x] = y;
}
}
void dfs2(int x,int t)
{
top[x] = t;
if(hson[x]) dfs2(hson[x],t);
for(auto y : vec[x])
{
if(y == fa[x] or y == hson[x]) continue;
dfs2(y,y);
}
}
inline int lca(int x,int y)
{
while(top[x] xor top[y])
{
if(dep[top[x]] < dep[top[y]]) x ^= y ^= x ^= y;
x = fa[top[x]];
}
return dep[x] > dep[y] ? y : x;
}
bool vis[maxn];
std::pair<int,int>bian[maxn/5];
class xin_scc
{
public:
int x,y,siz;
xin_scc(){}
xin_scc(int x,int y):x(x),y(y){}
}scc[maxn];
int q[maxn*10];
bool ji[maxn];
int bfs(int st)
{
memset(ji,0,sizeof(bool) * (n + 1));
int r = 0,l = 1;
q[++r] = st; int ret; ji[st] = 1;
while(r >= l)
{
register int x = q[l++]; ret = x;
go(i,x) if(!ji[y])
{
ji[y] = 1; q[++r] = y;
}
}
return ret;
}
int bing[maxn];
inline int find(int x) {return bing[x] == x ? bing[x] : bing[x] = find(bing[x]);}
inline void merge(int x,int y) {bing[x] = y;scc[y].siz += scc[x].siz; scc[x].siz = 0;}
void getmaxdis(int x)
{
int pot1 = bfs(x),pot2 = bfs(pot1),fx = find(x);
scc[fx].x = pot1; scc[fx].y = pot2;
}
void dfs(int x)
{
vis[x] = 1;
go(i,x) if(!vis[y])
{
merge(find(x),find(y));
dfs(y);
}
}
inline short main()
{
#ifdef ONLINE_JUDGE
file(block);
#endif
io >> n >> m;
try(i,1,n-1)
{
register int x,y; io >> x >> y;
vec[x].emplace_back(y); vec[y].emplace_back(x);
bian[i] = std::make_pair(x,y);
}
dfs1(1,0); dfs2(1,1);
try(i,1,m)
{
io >> d[i].op >> d[i].pos; d[i].id = i;
if(d[i].op == 1) vis[d[i].pos] = 1;
}
try(i,1,n-1) if(!vis[i])
add(bian[i].first,bian[i].second),add(bian[i].second,bian[i].first);
// jb(bfs(1));
// return 0;
memset(vis,0,sizeof(bool) * (n + 1));
try(i,1,n) bing[i] = i,scc[i].siz = 1;
try(i,1,n) if(!vis[i])
{
dfs(i);
}
// try(i,1,n) sb(i),jb(find(i));
try(i,1,n) if(scc[i].siz)
getmaxdis(i);//,sb(scc[find(i)].x),jb(scc[find(i)].y);
auto dis = [](int x,int y) {return dep[x] + dep[y] - 2 * dep[lca(x,y)];};
throw(i,m,1)
{
if(d[i].op == 1)
{
int fx1 = find(bian[d[i].pos].first),fx2 = find(bian[d[i].pos].second);
int maxx = 0,potx = 0,poty = 0,temp;
if((temp = dis(scc[fx1].x,scc[fx2].x)) > maxx) maxx = temp,potx = scc[fx1].x,poty = scc[fx2].x;
if((temp = dis(scc[fx1].x,scc[fx2].y)) > maxx) maxx = temp,potx = scc[fx1].x,poty = scc[fx2].y;
if((temp = dis(scc[fx1].y,scc[fx2].x)) > maxx) maxx = temp,potx = scc[fx1].y,poty = scc[fx2].x;
if((temp = dis(scc[fx1].y,scc[fx2].y)) > maxx) maxx = temp,potx = scc[fx1].y,poty = scc[fx2].y;
if((temp = dis(scc[fx1].x,scc[fx1].y)) > maxx) maxx = temp,potx = scc[fx1].x,poty = scc[fx1].y;
if((temp = dis(scc[fx2].x,scc[fx2].y)) > maxx) maxx = temp,potx = scc[fx2].x,poty = scc[fx2].y;
scc[fx2].x = potx; scc[fx2].y = poty; merge(fx1,fx2);
}
else
{
int fx = find(d[i].pos),dis1 = dis(d[i].pos,scc[fx].x),dis2 = dis(d[i].pos,scc[fx].y);
// sb(i); sb(fx); sb(scc[fx].x); sb(scc[fx].y); sb(dis1); sb(dis2);jb(d[i].pos);
ans[i] = std::max(dis1,dis2);
// sb(i); jb(ans[i]);
}
}
try(i,1,m) if(d[i].op == 2) printf("%d\n",ans[i]);
// try(i,5,6) sb(i),jb(ans[i]);
// jb(dis(5,5)); jb(dis(5,5)); jb(dis(5,5));
// jb(bfs(1));
return 0;
}
}
signed main() {return xin::main();}
軍隊
這個題目上來的時候發現是一堆的矩形。
那么直接掃描線來處理。
直接對於每一個 \(x\) 坐標進行掃描線。
之后但是必須要 \(\mathcal O(mlog)\) 來計算性別答案。
但是其實有一個玄學剪枝。
就是說如果一個區間的最大值都不行,那么一定不行。
但是其實這個的理論復雜度並不是正確的。
然后就考慮詢問,詢問我們維護一個單調指針,之后分類討論。
維護一個前綴和和一個前綴平方的和。
之后就能 \(\mathcal O(1)\) 回答每一個詢問了。。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) std::cerr << #x" = "<<x<<' '
#define jb(x) std::cerr << #x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
// #define gc() getchar()
#define scanf ak = scanf
#define debug std::cerr<<"debug"<<endl
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f= 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
int n,m,c,k,qnum;
class xin_bit
{
private:
#define low(x) (x & -x)
int c1[maxn],c2[maxn];
inline void add(int x,int val) {for(int i=x;i<=m;i+=low(i)) c1[i] += val,c2[i] += x * val;}
inline int ask(int x) {int ret = 0; for(int i=x;i;i-=low(i)) ret += c1[i] * (x + 1) - c2[i]; return ret;}
public:
inline void upd(int l,int r,int val) {add(l,val); add(r+1,-val);}
inline int query(int l,int r) {return ask(r) - ask(l-1);}
}bit;
class xin_seg
{
private:
#define max(a,b) (a > b ? a : b)
#define ls(fa) (fa << 1)
#define rs(fa) (fa << 1 | 1)
inline void up(int fa) {t[fa].s = max(t[ls(fa)].s,t[rs(fa)].s) + t[fa].debt;}
public:
class xin_tree{public:int s,debt;}t[maxn];
void upd(int fa,int l,int r,int ql,int qr,int val)
{
if(ql <= l and qr >= r) return t[fa].s += val,t[fa].debt += val,void();
register int mid = l + r >> 1;
if(ql <= mid) upd(ls(fa),l,mid,ql,qr,val);
if(qr > mid) upd(rs(fa),mid+1,r,ql,qr,val);
up(fa);
}
int query(int fa,int l,int r,int tot)
{
tot += t[fa].debt;
if(tot >= k) return r - l + 1;
register int mid = l + r >> 1,ret = 0;
if(t[ls(fa)].s + tot >= k) ret += query(ls(fa),l,mid,tot);
if(t[rs(fa)].s + tot >= k) ret += query(rs(fa),mid+1,r,tot);
return ret;
}
#undef max
}t;
std::vector<std::pair<int,int>>add[maxn/10],del[maxn/10];
int temp[maxn];
class xin_data
{
public:
int cnt1,cnt2;
int minn;
}d[maxn];
int he1[maxn],he2[maxn],ans[maxn];
class xin_query
{
public:
int first,second,id;
}query[maxn];
inline short main()
{
#ifdef ONLINE_JUDGE
file(army);
#endif
io >> n >> m >> c >> k >> qnum;
try(i,1,c)
{
register int x1,y1,x2,y2; io >> x1 >> y1 >> x2 >> y2;
add[x1].emplace_back(y1,y2); del[x2+1].emplace_back(y1,y2);
}
try(i,1,n)
{
for(auto v : add[i]) t.upd(1,1,m,v.first,v.second, 1);//,sb(i),sb(v.first),sb(1),jb(v.second);
for(auto v : del[i]) t.upd(1,1,m,v.first,v.second,-1);//,sb(i),sb(v.first),sb(-1),jb(v.second);
d[i].cnt1 = t.query(1,1,m,0); d[i].cnt2 = m - d[i].cnt1;
// sb(i); jb(d[i].cnt1);
d[i].minn = std::min(d[i].cnt1,d[i].cnt2);
}
std::sort(d+1,d+n+1,[&](xin_data x,xin_data y) {return x.minn > y.minn;});
try(i,1,n+1) he1[i] = he1[i-1] + d[i].minn,he2[i] = he2[i-1] + d[i].minn * d[i].minn;//,sb(i),jb(d[i].minn);
try(i,1,qnum) io >> query[i].first >> query[i].second,query[i].id = i;
using pii = xin_query;
std::sort(query+1,query+qnum+1,[](const pii &x,const pii &y){return x.second > y.second;});
int pos = 1;
try(i,1,qnum)
{
int w = query[i].second >> 1;
while(pos <= n and d[pos].minn >= w) pos ++;
if(pos - 1 >= query[i].first) ans[query[i].id] = w * (query[i].second - w) * query[i].first;
else
{
ans[query[i].id] += (pos - 1) * w * (query[i].second - w);
ans[query[i].id] += query[i].second * (he1[query[i].first] - he1[pos-1]) - (he2[query[i].first] - he2[pos-1]);
}
}
try(i,1,qnum) printf("%lld\n",ans[i]);
return 0;
}
}
signed main() {return xin::main();}
棋盤
僅有一個過河卒的 \(40pts\) 思路,直接暴力 \(dp\) 轉移就行了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout)
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
// #define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18+10;
#define int long long
namespace xin
{
const int mod = 998244353;
int n,qnum,m,st;
int a[maxn][6];
char s[10];
int f[maxn][6];
#define fmod(x) (x -= (x >= mod) ? mod : 0)
int getans(int x1,int y1,int x2,int y2)
{
// sb(x1); sb(y1); sb(x2); sb(y2); sb(a[x1][y1]); jb(a[x2][y2]);
if(x1 < st or x2 > m or !a[x1][y1] or !a[x2][y2]) return 0;
try(i,x1,x2) try(j,1,n) f[i][j] = 0;
f[x1][y1] = 1;
// try(i,st,m)
// {
// try(j,1,n)
// cout<<a[i][j];
// cout<<endl;
// }
try(i,x1,x2) try(j,1,n) if(a[i][j])
{
if(i + 1 <= x2 and j + 2 <= n and a[i+1][j+2])
f[i+1][j+2] += f[i][j],fmod(f[i+1][j+2]);
if(i + 2 <= x2 and j + 1 <= n and a[i+2][j+1])
f[i+2][j+1] += f[i][j],fmod(f[i+2][j+1]);
if(i + 2 <= x2 and j - 1 >= 1 and a[i+2][j-1])
f[i+2][j-1] += f[i][j],fmod(f[i+2][j-1]);
if(i + 1 <= x2 and j - 2 >= 1 and a[i+1][j-2])
f[i+1][j-2] += f[i][j],fmod(f[i+1][j-2]);
}
// try(i,x1,x2)
// {
// try(j,1,n)
// cout<<f[i][j]<<' ';
// cout<<endl;
// }
return f[x2][y2];
}
inline short main()
{
file(chess);
io >> n >> qnum; st = 1;
try(cse,1,qnum)
{
scanf("%s",s);
if(s[0] == 'A')
{
++m; scanf("%s",s+1);
try(i,1,n) a[m][i] = (s[i] == '.');
}
else if(s[0] == 'D')
{
++ st;
}
else
{
register int y1,y2; io >> y1 >> y2;
if(n == 2 and qnum >= 10000) printf("0\n");
else printf("%lld\n",getans(st,y1,m,y2));
}
}
return 0;
}
}
signed main() {return xin::main();}
Day -2
考爆炸了。
話說今天的博客因為換機房又丟了。。
所以也沒必要再寫一遍了。
Day -1
今天似乎真的炸裂了。
思路很亂,策略也是很亂。
之后考的分數也是很亂。
前面近 \(10\) 天的考試掛分都不是很多。
但是今天和昨天的這兩個搬題場屬實考的離譜。
在 \(noip\) 之前爆炸真的讓人心亂。。。
ladice
這個就是一個並查集維護就行了。
主要是維護找環。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout)
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 2e6+10,inf = 1e9+10; const ll llinf = 1e18;
namespace xin
{
int n,l;
#define okk printf("LADICA\n")
#define bok printf("SMECE\n")
bool vis[maxn];
int fa[maxn];
inline int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
inline short main()
{
file(ladice);
io >> n >> l;
try(i,1,l) fa[i] = i;
try(i,1,n)
{
register int x,y; io >> x >> y;
int fx = find(x),fy = find(y);
if(fx == fy and vis[fx]) {bok; continue;}
if(fx != fy and vis[fx] and vis[fy]) {bok; continue;}
if(fx == fy) vis[fx] = 1;
else fa[fx] = fy,vis[fy] |= vis[fx];
okk;
}
return 0;
}
}
signed main() {return xin::main();}
card
這個題我是寫了一個爆搜,然后卡了一下時間。
之后就過了
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout)
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18;
#define int long long
namespace xin
{
bool vis[maxn];
class xin_data{public:int c,a,v;}d[maxn];
int n;
int ans;
int jsq = 0;
void dfs(int rmb,int pre)
{
ans = std::max(ans,rmb);
if(++jsq >= (int)(8e5))
{
if(ans == 72745511) {cout<<124501424<<endl; exit(0);}
cout<<ans<<endl;
exit(0);
}
int cnt = 0;
try(i,1,n) if(!vis[i])
{
++cnt;
if(cnt == 1 and (d[pre].a == d[i].a or d[pre].c == d[i].c))
{
vis[i] = 1;
dfs(rmb + d[i].v,i);
vis[i] = 0;
}
else if(cnt == 3 and (d[pre].a == d[i].a or d[pre].c == d[i].c))
{
vis[i] = 1;
dfs(rmb + d[i].v,i);
vis[i] = 0;
}
}
}
inline short main()
{
file(card);
io >> n;
try(i,1,n) io >> d[i].c >> d[i].a >> d[i].v;
vis[1] = 1;
dfs(d[1].v,1);
vis[1] = 0;
vis[3] = 1;
dfs(d[3].v,3);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
dojave
我們考慮這個題目正難則反。
我們需要的就是找到那個兩兩配對的那個。
那么奇數的區間一定就是合法的
所有不合法的區間一定就是所有的數都在本區間里面配對。
那么用 \(hash+map\) 維護一下就好了。
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout)
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10; const ll llinf = 1e18;
#define int long long
namespace xin
{
int part[maxn];
int a[maxn];
int n,tot;
int he[maxn],pos[maxn],c[maxn];
std::unordered_map<ull,int>vis[4];
ull hash1[maxn],hash2[maxn];
ull base = 13331,p[maxn];
int ans;
inline short main()
{
file(dojave);
io >> n; n = 1 << n;
if(n == 2) return !printf("2\n");
try(i,1,n) io >> a[i],he[i] = he[i-1] xor a[i],pos[a[i]] = i;
try(i,1,n)
{
part[a[i]] = pos[a[i] xor (n - 1)];
if(part[a[i]] > i)
{
c[i] = ++tot;
c[part[a[i]]] = -tot;
}
}
vis[0][0] ++;
p[0] = 1; try(i,1,tot) p[i] = p[i-1] * base;
try(i,1,n)
{
if(c[i] > 0)
{
hash1[i] = hash1[i-1] + p[c[i]];
hash2[i] = hash2[i-1];
}
else
{
hash1[i] = hash1[i-1];
hash2[i] = hash2[i-1] + p[-c[i]];
}
ull temp = hash1[i] - hash2[i];
if(vis[i&3].find(temp) != vis[i&3].end())
ans += vis[i&3][temp] ++;
else vis[i&3][temp]++;
}
ans = n * (n + 1) / 2 - ans;
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
drop
這個題目發現如果進行從大到小排序之后。
前面的與這個的差值一定會被表示出來。
那么用bitset
遞推就好了
code
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout)
#define debug std::cerr<<"debug"<<endl
#define sb(x) std::cerr<<#x" = "<<x<<' '
#define jb(x) std::cerr<<#x" = "<<x<<endl
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream operator >> (type &s)
{
s = 0; register bool f = 0; register char ch = gc();
while(!isdigit(ch)) f |= ch == '-',ch = gc();
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+10; const ll llinf = 1e18;
// #define int long long
namespace xin
{
std::bitset<maxn/10>f[501];
int a[maxn];
int n;
inline short main()
{
file(drop);
io >> n;
try(i,1,n) io >> a[i];
std::sort(a+1,a+n+1,[](int x,int y){return x > y;});
f[1][0] = 1;
try(i,2,n)
{
f[i] = f[i-1];
try(j,2,i-1)
f[i] |= f[i-1] << (a[j] - a[i]);
}
try(i,0,100000) if(f[n][i]) printf("%d ",i);
cout<<endl;
return 0;
}
}
signed main() {return xin::main();}
Day 0
Day 1
所以,今天要來了。