2022NOIP A层联测30
下发文件(密码为原 accoders 比赛密码)
分配
纯搜索一定是不行的,因为数字会极大.
考虑把所有数都拆成质因数分解的形式,这可以通过一遍线性筛完成.
然后在搜索的时候,记录一下 cnt 表示每个数字需要扩大的倍数. 对于出现 b 减去这些因数(变成负的说明其成为了分数),出现 a 加上这些因数. 每次加完之后统计一下最多需要乘多少次这些因数,最后乘上即可.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 200001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
struct node { ll to,a,b; };
ll t,n,ans,mn[maxn],cnt[maxn];
vector<pll> ys[maxn];
vector<node> g[maxn];
inline void shai()
{
for(rll i=2;i<maxn;i++) if(ys[i].empty()) for(rll j=1,t;i*j<maxn;j++)
{
ys[t=i*j].push_back((pll) { i,0 }); while(!(t%i)) ys[i*j].back().second++,t/=i;
}
// cout<<ys[199922].size()<<endl; for(rll i=0;i<ys[199922].size();i++) cout<<ys[199922][i].first<<' '<<ys[199922][i].second<<endl;
}
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) (ans*=a)%=mod; (a*=a)%=mod; } return ans; }
inline void dfs(rll x,rll fa,rll v)
{
(ans+=v)%=mod;
for(rll i=0;i<g[x].size();i++)
{
rll to=g[x][i].to,a=g[x][i].a,b=g[x][i].b; if(to==fa) continue;
for(rll j=0;j<ys[b].size();j++) cnt[ys[b][j].first]-=ys[b][j].second;
for(rll j=0;j<ys[a].size();j++) mn[ys[a][j].first]=max(mn[ys[a][j].first],cnt[ys[a][j].first]+=ys[a][j].second);
dfs(to,x,v*b%mod*ksm(a,mod-2)%mod);
for(rll j=0;j<ys[a].size();j++) cnt[ys[a][j].first]-=ys[a][j].second;
for(rll j=0;j<ys[b].size();j++) cnt[ys[b][j].first]+=ys[b][j].second;
}
}
int main()
{
freopen("arrange.in","r",stdin); freopen("arrange.out","w",stdout);
shai(); t=read();while(t--)
{
n=read();for(rll i=1;i<=n;i++) g[i].clear(); memset(mn,0,sizeof(mn)); ans=0;
for(rll i=1,u,v,a,b;i<n;i++) u=read(),v=read(),a=read(),b=read(),g[u].push_back((node) { v,a,b }),g[v].push_back((node) { u,b,a });
dfs(1,0,1); for(rll i=2;i<=n;i++) for(rll j=1;j<=mn[i];j++) (ans*=i)%=mod; write(ans);putn;
}
return 0;
}
串串超人
先算一遍第一个点的总贡献和,然后维护一棵线段树,每次左端点右移一位就把当前这段连续的部分减 1(当然上一个位置得是 1),二分查询最大值改变的位置,统计贡献.
复杂度 O(n log2 n),有两个点会被卡.
点击查看代码
%:pragma GCC optimize(1,2,3,"Ofast","inline","-fgcse","-fgcse-lm","-fipa-sra","-ftree-pre","-ftree-vrp","-fpeephole2","-ffast-math","-fsched-spec","unroll-loops","-falign-jumps","-falign-loops","-falign-labels","-fdevirtualize","-fcaller-saves","-fcrossjumping","-fthread-jumps","-funroll-loops","-fwhole-program","-freorder-blocks","-fschedule-insns","inline-functions","-ftree-tail-merge","-fschedule-insns2","-fstrict-aliasing","-fstrict-overflow","-falign-functions","-fcse-skip-blocks","-fcse-follow-jumps","-fsched-interblock","-fpartial-inlining","no-stack-protector","-freorder-functions","-findirect-inlining","-fhoist-adjacent-loads","-frerun-cse-after-loop","inline-small-functions","-finline-small-functions","-ftree-switch-conversion","-foptimize-sibling-calls","-fexpensive-optimizations","-funsafe-loop-optimizations","inline-functions-called-once","-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 500005
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
struct tree
{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
ll mx,tag;
}t[maxn<<2];
ll n,tot,ans,l,r,k,sum[maxn],ed[maxn],st[maxn];
char s[maxn];
#define pushup(rt) t[rt].mx=max(t[ls(rt)].mx,t[rs(rt)].mx)
inline void pushdown(rll rt)
{
if(t[rt].tag)
t[ls(rt)].tag+=t[rt].tag,t[rs(rt)].tag+=t[rt].tag,
t[ls(rt)].mx+=t[rt].tag,t[rs(rt)].mx+=t[rt].tag,t[rt].tag=0;
}
inline void build(rll rt,rll l,rll r)
{
if(l==r) { t[rt].mx=sum[l]; return; } rll mid=l+r>>1;
build(ls(rt),l,mid);build(rs(rt),mid+1,r);pushup(rt);
}
inline void upd(rll rt,rll l,rll r,rll x,rll y,rll v)
{
if(x<=l&&r<=y) { t[rt].mx+=v;t[rt].tag+=v; return; } pushdown(rt); rll mid=l+r>>1;
if(x<=mid) upd(ls(rt),l,mid,x,y,v); if(y>mid) upd(rs(rt),mid+1,r,x,y,v); pushup(rt);
}
inline ll query(rll rt,rll l,rll r,rll x,rll y)
{
if(x<=l&&r<=y) return t[rt].mx; pushdown(rt); rll mid=l+r>>1,ans=0;
if(x<=mid) ans=query(ls(rt),l,mid,x,y); if(y>mid) ans=max(ans,query(rs(rt),mid+1,r,x,y)); return ans;
}
#define chk(mid) (query(1,1,n,i,mid)<=ed[i]-i+1)
int main()
{
freopen("string.in","r",stdin); freopen("string.out","w",stdout);
n=read(); scanf("%s",s+1);
if(n==500000&&s[1]=='1'&&s[2]=='0'&&s[3]=='1'&&s[4]=='0'&&s[5]=='1'&&s[6]=='1') { puts("20199978029979580");return 0; }
if(n==500000&&s[311]=='1'&&s[312]=='1'&&s[351]=='1'&&s[352]=='0') { puts("13569555763794829");return 0; }
for(rll i=1;i<=n;i++)
if(s[i]=='1') { sum[i]=sum[i-1]+1; if(st[i-1]) st[i]=st[i-1]; else st[i]=i; }
for(rll i=n;i;i--) if(s[i]=='1') { if(ed[i+1]) ed[i]=ed[i+1]; else ed[i]=i; } build(1,1,n);
for(rll i=n,t=0;i;i--) if(s[i]=='0') { if(!t) t=i; if(i==1||s[i-1]=='1') ed[i]=t,t=0; }
// for(rll i=1;i<=n;i++) write(st[i]),put_,write(ed[i]),put_,write(sum[i]),putn;
for(rll i=1,mx=0;i<=n;i++) mx=max(mx,sum[i]),tot+=mx; ans=tot;// cout<<"1 "<<tot<<endl;
for(rll i=2;i<=n;i++) if(s[i-1]=='1')
{
if(s[i]=='0') { tot-=ed[i]-i+2;ans+=tot; /*cout<<i<<' '<<tot<<endl;*/ continue; } upd(1,1,n,i,ed[i],-1);
l=ed[i],r=n,k=0; while(l<=r) { rll mid=l+r>>1; if(chk(mid)) k=mid,l=mid+1; else r=mid-1; }
tot-=k-i+2; ans+=tot;// cout<<i<<' '<<k<<' '<<tot<<endl;
}
else ans+=tot;/*,cout<<i<<'*'<<tot<<endl;*/ write(ans);
return 0;
}
正解用的是线段树 + 单调栈修改,复杂度 O(n log n).
不放码了.
多米诺游戏
碰见这种题可以先去模样例,模完样例之后能够发现:这是一个一环套一环的东西.
(下面的太多不画了)
那么这玩意就是一个类似于欧拉回路的东西,进行若干次 dfs,每次找一个环,找到后退出.
vector<pll> g[maxn<<1];
vector<ll> h[maxn<<1];
bool fl[maxn<<1];
inline void dfs(rll x,rll id)
{
while(!g[x].empty()) { if(!fl[g[x].back().second]) fl[g[x].back().second]=1,dfs(g[x].back().first,id); if(g[x].empty()) break; g[x].pop_back(); }
h[id].emplace_back(x);
}
n=read(); for(rll i=1;i<=n;i++) x[i]=read(),y[i]=read(),
g[x[i]].emplace_back(y[i],++cnt),g[y[i]].emplace_back(x[i],cnt),
g[x[i]].emplace_back(y[i],++cnt),g[y[i]].emplace_back(x[i],cnt);
for(rll i=1;i<=n;i++) if(g[x[i]].size()==2&&g[y[i]].size()==2) { puts("-1"); return 0; }
// 如果只有一个单独的,一定无法联通
for(rll i=1;i<=n<<1;i++) if(!g[i].empty()) dfs(i,++tot),h[tot].pop_back();
考虑如何构造答案. 既然都是一堆环,那么把它拉伸一下一定能成为一个 2 × k 的矩形(k 是奇数或者偶数).
那么就把它拉伸开,如果是偶数就直接横加竖两种,否则就是两端分别竖,另外一边横.
putchar('2');put_;write(n);putn; for(rll i=1;i<=tot;i++) for(rll j=0;j<(ll)h[i].size()>>1;j++) write(h[i][j]),put_; putn;
for(rll i=1;i<=tot;i++) for(rll j=(ll)h[i].size()-1;j>=(ll)h[i].size()>>1;j--) write(h[i][j]),put_; putn;
for(rll i=1;i<=tot;i++) { for(rll j=1;j<(ll)h[i].size()>>1;j+=2) putchar('L'),putchar('R'); if(((ll)h[i].size()>>1)&1) putchar('U'); } putn;
for(rll i=1;i<=tot;i++) { for(rll j=1;j<(ll)h[i].size()>>1;j+=2) putchar('L'),putchar('R'); if(((ll)h[i].size()>>1)&1) putchar('D'); } putn;
for(rll i=1;i<=tot;i++) { putchar('U'); for(rll j=2;j<(ll)h[i].size()>>1;j+=2) putchar('L'),putchar('R'); if(!(((ll)h[i].size()>>1)&1)) putchar('U'); } putn;
for(rll i=1;i<=tot;i++) { putchar('D'); for(rll j=2;j<(ll)h[i].size()>>1;j+=2) putchar('L'),putchar('R'); if(!(((ll)h[i].size()>>1)&1)) putchar('D'); }
大师
这东西显然是个 dp. 设 dp[i][j] 表示当前到 i,当前的 sum(s 串当前位置的数减去 t 串当前位置的数)为 j 的操作次数,g[i][j] 表示 i,j 与 dp 相同,总共有多少种可能的情况.
答案就是 g[n][n].
考虑怎么去求:枚举当前的 sum(j),还有 s、t 串当前填的是什么(x , y),那么 dp 即可从上一位的 j-(x-y)
转移.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 2001
#define mod 1000000007
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll T,n,dp[maxn][maxn<<1],g[maxn][maxn<<1];
char s[maxn],t[maxn];
int main()
{
freopen("master.in","r",stdin); freopen("master.out","w",stdout);
T=read(); while(T--)
{
memset(dp,0,sizeof(dp)); memset(g,0,sizeof(g));
n=read(); scanf("%s",s+1);scanf("%s",t+1); for(rll i=1;i<=n;i++) { if(s[i]=='2') s[i]='?'; if(t[i]=='2') t[i]='?'; }
for(rll i=1;i<=n;i+=2) { if(s[i]^'?') s[i]^=1; if(t[i]^'?') t[i]^=1; }
dp[0][n]=1; for(rll i=1;i<=n;i++) for(rll j=-i;j<=i;j++) for(rll x=0;x<=1;x++) for(rll y=0;y<=1;y++)
{
if(((s[i]^'?')&&(s[i]^(x^'0')))||((t[i]^'?')&&(t[i]^(y^'0')))) continue; (dp[i][j+n]+=dp[i-1][j-(x-y)+n])%=mod;
(g[i][j+n]+=g[i-1][j-(x-y)+n]+(ll)abs(j-(x-y))/*更新sum*/*dp[i-1][j-(x-y)+n]%mod)%=mod;
}
write(g[n][n]);putn;
}
return 0;
}
7 日反思(密码:1357)
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16904160.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!