10.27 CSP-S模拟40 改题记录
写在前面
没想到离CSP还有4天然后创造了一次保龄的经历。。。然后就是读假题专场。其实感觉没有太难但是。。。好吧,碍于时间不多,也不说废话了。
A. 公约数神庙
我无言。我以为我败在了空间,结果其实是败给了糖错和可恶的特判。难得想出正解呜呜呜。题意是有一个数列,从编号小的到编号大的且公因数大于1的点对有有向边。给出询问一个点对是否能通达。
读假题,还说终于来签到题了。还好样例善良。肯定不考虑暴力建边,暴力转移也不可取。观察到\(i\) 可以通过中转点走到\(j\)。由于保证了从编号小的点走到编号大的点,我们考虑倒着维护通达性。观察到值域内每个数至多有4个质因数,共有168个质因数。由于从某个位置开始,就算一个数不含某个质因数也能通过中转点走到含有该质因子的位置,我们考虑维护每个质因数的数从哪个位置开始能走到另一个质因数的倍数上,动态加入取min即可。然后每个询问就枚举终点的质因数看其是否在起点可通达范围内即可。然后难点还没来,难点在特判。全场因为特判的问题挂了inf分。
B. 栈法师
读假题\(\times 2\)。甚至还写了1h。
题意是给出一个起始栈,构造一系列操作,使得栈内元素在终止栈内升序排列,且要求过渡栈的量最小。
省略读假题的内容。显然过渡栈的数量最多是2。考虑是1的情况,直接做看看能否满足要求即可。否则考虑先将所有元素放到一个过渡栈,这样每次操作都是有规律的不用特判。然后我们肯定要从小到大弹进终止栈,如果其上方有比其大的数肯定需要到过渡栈里待避,我们预处理出这个值即可。然后要弹出一个元素我们就先将其上方元素弹入另一个过渡栈,再将该元素弹出,再将过渡栈元素弹回去,就能减少分讨了。其实没有任何技术含量可言。
C. 城堡考古
改了inf小时没改完。先存下代码和题解。
需要写一个高精度的10->2进制转换(可以每次暴力做高精度除22,复杂度是对的),位数大概\(\times3\) 题目要求的是一个差分形式,需要矩阵多开一维记录前缀 sum直接实现的话大概能跑65分。
按照网格状压DP的套路,有很多状态其实是到不了的,dfs 预处理合法且能够从 s=0s=0 到达的状态,发现只有20个(其实是一个组合数,mm 列恰有 \(\binom{m}{m/2}\) 个合法状态)。
复杂度变为 \(O(20^3\times len)\),这样就能通过了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100,mod=998244353;
int dp[maxn][maxn];
string sl,sr;
bitset<10000> l,r;
int m;
struct matrix{
int a[30][30];
matrix(){
memset(a,0,sizeof(a));
}
inline matrix operator*(const matrix &b)const{
matrix c;
for(int i=1;i<=m;i++){
for(int k=1;k<=m;k++){
int p=a[i][k];
for(int j=1;j<=m;j++)
c.a[i][j]=(c.a[i][j]+1ll*p*b.a[k][j]%mod)%mod;
}
}
return c;
}
}ll,rr,aa;
inline void qpow(matrix &a,matrix b,bitset<10000> y){
for(int i=0;i<10000;i++){
if(y[i]) a=a*b;
b=b*b;
}
}
inline string div(string &s){
string ss="";
int now=0;
for(int i=0;i<s.size();i++){
now=now*10+s[i]-'0';
if(now==1&&i<s.size()-1) continue;
ss+=now/2+'0';
now%=2;
}
return ss;
}
inline void get2(string &s,bitset<10000> &c){
for(int i=0;;i++){
if((s[s.size()-1]-'0')&1){
c[i]=1;
}
s=div(s);
if(s[0]=='0') break;
}
}
bool vis[70];
inline void dfs(int las,int lv){
vis[las]=1;
if(lv>=5) return;
for(int i=0;i<(1<<m);i++){
bool flg=1;
int cnt=0;
for(int j=0;j<m;j++)
if(((i>>j)&1)&&((las>>j)&1)){
flg=0;
break;
}
else if(((i>>j)&1)||((las>>j)&1)){
if(cnt&1){
flg=0;
break;
}
cnt=0;
}
else ++cnt;
if(cnt&1) flg=0;
if(flg) dfs(i,lv+1);
}
}
vector<int> legal;
bool start[70];
inline bool check(int x,int y){
int cnt=0;
for(int i=0;i<m;i++)
if((((x>>i)&1)&&((y>>i)&1))) return 0;
else if(((x>>i)&1)||((y>>i)&1)){
if(cnt&1) return 0;
cnt=0;
}
else ++cnt;
if(cnt&1) return 0;
return 1;
}
int main(){
freopen("decoration.in","r",stdin);
freopen("decoration.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>sl;
cin>>sr;
cin>>m;
for(int i=sl.size()-1;i>=0;i--){
sl[i]--;
if(sl[i]>='0') break;
sl[i]+=10;
}
if(sl[0]=='0'){
string ss=sl;
sl="";
for(int i=1;i<ss.size();i++) sl+=ss[i];
}
int cnt=0;
get2(sl,l);
get2(sr,r);
if(m==1) vis[0]=vis[1]=1,cnt=2;
else{
for(int i=0;i<(1<<m);i++){
vis[i]=1;
int cnt=0;
for(int j=0;j<m;j++)
if((i>>j)&1){
if(cnt&1){
vis[i]=0;
break;
}
cnt=0;
}
else ++cnt;
if(cnt&1) vis[i]=0;
if(vis[i]) start[i]=1,dfs(i,0);
}
for(int i=0;i<(1<<m);i++)
if(vis[i]){
legal.emplace_back(i),++cnt;
if(start[i]) ll.a[cnt][1]=rr.a[cnt][1]=1;
}
}
for(int i=0;i<legal.size();i++)
for(int j=0;j<legal.size();j++)
if(check(legal[i],legal[j])) aa.a[i+1][j+1]=1;//,cout<<legal[i]<<' '<<legal[j]<<'\n';
// ll=aa*ll;
// cout<<ll.a[1][1]<<' '<<ll.a[2][2]<<'\n';
qpow(ll,aa,l);
qpow(rr,aa,r);
int ans=0;
for(int i=1;i<=cnt;i++) ans=(ans+rr.a[i][1])%mod;
// cout<<ans<<'\n';
for(int i=1;i<=cnt;i++) ans=(ans-ll.a[i][1])%mod;
cout<<(ans%mod+mod)%mod;
return 0;
}
D. 生命之树
感觉做过原题。然后咕了(其实是贺了题解式子然后自己懒得没空详写)。哦哦对了,大概就是打了15min暴力还没来得及交然后一脚把机箱电源踹了

浙公网安备 33010602011771号