[考试总结]noip模拟53
ZYB和售货机
题目描述的很麻烦,说实话就是这个东西有依赖关系,然后构成一个图
然后我们每次找到连接每个点的最大值与次大值,之后我们沿着最大值去找环。
发现环之后我们是一定要去断开的。
这时候我们用次大值去替换一定是最优的。
所以就是了。
然后计算可以获得的最大收益。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed 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(a) freopen(#a".in","r",stdin),freopen(#a".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 = 1e6+10,inf = 1e9+7;const ll llinf = 1e18+7;
namespace xin
{
auto min = [](int x,int y) -> int {return x < y ? x : y;};
ll ans;
int n,num,minn;
int fir[maxn],sec[maxn],a[maxn],c[maxn],f[maxn],d[maxn],val[maxn],vis[maxn];
auto dfs = [](int x) -> void
{
while(1)
{
if(vis[x]) return ans -= (vis[x] == num) * minn,void();
vis[x] = num ;if(!fir[x]) return ;
ans += 1ll * val[fir[x]] * a[x]; minn = min(minn,val[fir[x]] - val[sec[x]]);
if(x xor fir[x]) x = fir[x]; else return;
}
};
inline short main()
{
file(goods);
;;;;;
io >> n;
try(i,1,n) io >> f[i] >> c[i] >> d[i] >> a[i];
try(i,1,n)
{
val[i] = d[f[i]] - c[i];
if(val[i] > val[fir[f[i]]]) sec[f[i]] = fir[f[i]],fir[f[i]] = i;
else if(val[i] > val[sec[f[i]]]) sec[f[i]] = i;
}
try(i,1,n) if(!vis[i]) ++num,minn = inf,dfs(i);
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
ZYB玩字符串
这个题目还是的解法比较新颖
我们这个的解法是用一个区间 \(dp\) 来判断其合法性。
复杂度自然是很高。
但是完全是跑不满的。
转移方程:
\[f_{i,j} |= f_{i,j-1} and\; [prefix_{(j-i) mod \;len+1} ] \\
f_{i,j} |= f_{i,j-k*len}\;and\;f_{j-k*len+1,j}
\]
然后我们判重一下就好了。。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed 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(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#define scanf ak = scanf
#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 = 1e3+10,inf = 1e9+7;const ll llinf = 1e18+7;
namespace xin
{
bool f[maxn][maxn];
char s[maxn],prefix[maxn],ans[maxn],temp[maxn];
int T,n;
int yue[maxn];
std::vector<char>vec;
std::map<std::vector<char>,int>vis;
auto check = [](int l,int r) -> bool
{
try(i,0,n) {memset(f[i],0,sizeof(int) * (n + 1));}
try(i,l,r) prefix[i - l + 1] = s[i];
try(i,1,n) if(s[i] == s[l]) f[i][i] = 1;
int length = r - l + 1;
try(len,1,n) try(i,1,n - len + 1)
{
register int j = i + len - 1;
f[i][j] |= f[i][j-1] & (prefix[(j - i) % length + 1] == s[j]);
for(register int k=1;k<=j/length;++k)
f[i][j] |= f[i][j - k * length] & f[j-k*length+1][j];
}
return f[1][n];
};
auto comp = [](int len) -> bool
{
if(!strlen(ans)) return 1;
try(i,1,len) if(temp[i] > ans[i]) return 1;
return 0;
};
auto record = [](int l,int r) -> void
{
try(i,l,r) temp[i - l + 1] = s[i];
if(comp(r - l + 1)) {try(i,1,r-l+1) ans[i] = temp[i];ans[r-l+2] = '\0';}
};
auto div = [](int x) -> void
{
int ms = std::sqrt(x); yue[0] = 0;
try(i,1,ms) yue[++yue[0]] = i,yue[++yue[0]] = x / i;
std::sort(yue+1,yue+yue[0]+1);
};
inline short main()
{
file(string);
scanf("%d",&T);
while(T--)
{
scanf("%s",s+1); n = strlen(s + 1); bool ok = 0;
// jb(check(4,8));
div(n); vis.clear();
try(i,1,yue[0]) {int len = yue[i]; try(l,1,n - len + 1)
{
if(ok) break;
register int r = l + len - 1;
vec.clear();
try(i,l,r) vec.push_back(s[i]);
if(!vis[vec]) vis[vec] = 1;
else continue;
if(check(l,r)) {record(l,r); ok = 1;}
}}
printf("%s\n",ans+1);
}
return 0;
}
}
signed main() {return xin::main();}
午餐
似乎挺像吵闹少年团的那个题目
那就是有限制的 \(dij\) 就行了呗。。。
%: pragma GCC optimize(3)
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed 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(a,b) freopen(#a"","r",stdin),freopen(#b"","w",stdout)
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#define scanf ak = scanf
#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 = 1e6+10,inf = 1e9+7;const ll llinf = 1e18+7;
namespace xin
{
#define mp std::make_pair
class xin_edge{public:int next,ver,maxx,minn;}edge[maxn];
class xin_data{public:int x,y,l,r;}d[maxn];
int head[maxn],rp;
auto add = [](int x,int y,int maxx,int minn) -> void{edge[++rp].ver = y ;edge[rp].maxx = maxx; edge[rp].minn = minn;edge[rp].next = head[x]; head[x] = rp;};
auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
int n,m; std::queue < int > q;
int tar[maxn],lim[maxn],dis[maxn]; bool vis[maxn];
auto spfa = []() -> void
{
while(q.size())
{
register int x = q.front(); q.pop();
go(i,x) {register int mx = edge[i].maxx,mn = edge[i].minn; if(lim[x] > mx and lim[y] <= mn) {lim[y] = mn + 1; if(!vis[y]) vis[y] = 1,q.push(y);}}
vis[x] = 0;
}
};
auto dijkstra = []() -> void
{
std::priority_queue<std::pair<int,int>,std::vector<std::pair<int,int> >,std::greater<std::pair<int,int> > > q;
memset(vis,0,sizeof(bool) * (n + 1)); memset(dis,0x3f,sizeof(int) * (n + 1)); dis[1] = 0; q.push(mp(0,1));
while(q.size())
{
register int x = q.top().second; q.pop(); vis[x] = 1;
go(i,x)
{
register int mx = edge[i].maxx,mn = edge[i].minn,temp = max(dis[x],max(lim[y],mn));
if(temp < dis[y] and temp <= mx) dis[y] = temp,q.push(mp(dis[y],y));
}
while(q.size() and vis[q.top().second]) q.pop();
}
};
inline short main()
{
file(lunch.in,lunch.out);
io >> n >> m;
try(i,1,m) io >> d[i].x >> d[i].y >> d[i].l >> d[i].r,add(d[i].x,d[i].y,d[i].r,d[i].l),add(d[i].y,d[i].x,d[i].r,d[i].l);
try(i,1,n) {io >> tar[i]; if(!(~tar[i])) vis[i] = 1,q.push(i),lim[i] = inf; else vis[i] = 0;}
auto judge = []() -> void
{
try(i,1,n) if(tar[i] == 1 and dis[i] > inf) {puts("Impossible"); exit(0);}
try(i,1,m)
{
register int x = d[i].x,y = d[i].y;
if((!(~tar[x]) and dis[y] <= d[i].l) or (!(~tar[y]) and dis[x] <= d[i].l)) {puts("Impossible");exit(0);}
}
};
spfa(); dijkstra(); judge();
try(i,1,m)
{
register int x = d[i].x,y = d[i].y;
if(!(~tar[x]) or !(~tar[y])) printf("%d\n",d[i].l);
else printf("%d\n",max(dis[x],dis[y]) > d[i].r ? d[i].l : max(d[i].l,max(dis[x],dis[y])));
}
return 0;
}
}
signed main() {return xin::main();}
计数
这个我们首先考虑一个没有限制的做法。
我们设 \(f_i\) 为子树大小为 \(i\),然后方案数为 \(f_i\)。
转移:
\[f_0 = 1\\
f_i = \sum_{j=0}^{n} f_j * f_{n-j-1}
\]
然后 \(20pts\) 到手。。。
然后我们推广
有限制了就是限制其深度。。
然后记录一个 \(lim\) 也就能转移了
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed 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(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".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 = 1e3+10,inf = 1e9+7;const ll llinf = 1e18+7;
#define int long long
auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
namespace xin
{
int mod = inf;
int n,T,m;
int f[maxn],dp[maxn][maxn],lim[maxn][3];
int dfs(int i,int j)
{
if(~dp[i][j]) return dp[i][j]; if(!j) return 1;
dp[i][j] = 0;
try(k,max(lim[i][0],0),min(lim[i][1],j-1))
(dp[i][j] += dfs(i+1,k) * dfs(i+1+k,j-1-k) % mod) %= mod;
return dp[i][j];
}
inline short main()
{
file(count);
io >> T;
while(T--)
{
io >> n >> m;
if(!m)
{
f[0] = 1; f[1] = 1;
try(i,2,n) try(j,0,i-1)
(f[i] += f[j] * f[i-j-1] % mod) %= mod;
cout<<f[n]<<endl;
memset(f,0,sizeof(int) * (n + 1));
continue;
}
try(i,1,n) {lim[i][0] = 0,lim[i][1] = n - i + 1;}
memset(dp,-1,sizeof(dp));
try(i,1,m)
{
register int x,y; io >> x >> y;
if(x < y) lim[x][1] = min(lim[x][1],y - x - 1);
else lim[y][0] = max(lim[y][0],x - y);
}
printf("%lld\n",dfs(1,n));
}
return 0;
}
}
signed main() {return xin::main();}