NOIP模拟三
傻逼subtask能不能滚出OI赛制,妈的出题人也是傻逼四道题全是subtask
link
T1
赛时脑子抽了想到做法实现错了。
给每一行每一列上个标记,交换的时候更改标记就行了,没了。
还有妈的每次一遍快速幂还被卡了……
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=5005,M=1919810,mod=998244353;
ll n,m,q;
ll a[N][N];
ll tag[N][N],tagr[N],tagc[N];
ll q17[N],q19[N];
char c[M];
uint64_t seed;
uint64_t next(){
seed^=seed<<13;
seed^=seed>>7;
seed^=seed<<17;
return seed;
}
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans%mod;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m>>q>>seed;
for(int i=1;i<=q;++i) cin>>c[i];
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=(i-1)*m+(j-1);
q17[0]=q19[0]=1;
for(int i=1;i<=n;++i) q17[i]=q17[i-1]*17%mod,tagr[i]=i;
for(int i=1;i<=m;++i) q19[i]=q19[i-1]*19%mod,tagc[i]=i;
//妈的还能这么卡,傻逼
for(int i=1;i<=q;++i){
ll r1,r2,c1,c2;
if(c[i]=='r'){
r1=next()%n,r2=next()%n;
r1++,r2++;
swap(tagr[r1],tagr[r2]);
}
if(c[i]=='c'){
c1=next()%m,c2=next()%m;
c1++,c2++;
swap(tagc[c1],tagc[c2]);
}
if(c[i]=='f'){
r1=next()%n,c1=next()%m,r2=next()%n,c2=next()%m;
r1++,r2++,c1++,c2++;
swap(a[tagr[r1]][tagc[c1]],a[tagr[r2]][tagc[c2]]);
}
}
ll ans=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
ans=(ans+(a[tagr[i]][tagc[j]]%mod*q17[i-1]%mod*q19[j-1])%mod)%mod;
cout<<ans;
return 0;
}
T2
还以为是一个巨大的分类讨论,结果正解是一个很简洁的差分约束。记录每对点之间的最大最小差值 ,然后跑一遍Floyd求出来。最后分类讨论一下满足三种情况的条件就好了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=114,M=1919810;
ll n,a,b;
ll maxn[N][N],minn[N][N]; //差值最大最小
//啊啊啊啊啊差分约束啊啊
ll ans1,ans2,ans3;
int main(){
cin>>n;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
char ch; cin>>ch;
if(i==j||ch=='=') maxn[i][j]=minn[i][j]=0;
if(ch=='+') maxn[i][j]=2,minn[i][j]=1;
if(ch=='-') maxn[i][j]=-1,minn[i][j]=-2;
if(ch=='?'&&i!=j) maxn[i][j]=2,minn[i][j]=-2;
}
for(int k=1;k<=n;++k) //Floyd应该这样写????
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
maxn[i][j]=min(maxn[i][j],maxn[i][k]+maxn[k][j]),
minn[i][j]=max(minn[i][j],minn[i][k]+minn[k][j]);
cin>>a>>b;
for(int x=1;x<=n;++x)
for(int y=1;y<x;++y){
if(x==a||y==a||x==b||y==b) continue;
if(minn[a][x]>maxn[y][b]||minn[a][y]>maxn[x][b]) ++ans1;
if(minn[a][x]==maxn[a][x]&&maxn[a][x]==maxn[y][b]&&maxn[y][b]==minn[y][b]) ++ans2;
else if(minn[b][x]==maxn[b][x]&&maxn[b][x]==maxn[y][a]&&maxn[y][a]==minn[y][a]) ++ans2;
if(maxn[a][x]<minn[y][b]||maxn[a][y]<minn[x][b]) ++ans3;
}
cout<<ans1<<" "<<ans2<<" "<<ans3;
return 0;
}
T3
转化成以 的代价覆盖 和所有满足 的 ,然后dp出来两行被覆盖的极长前缀长度,转移的时候考虑 要不要贴不贴,然后可以用树状数组维护达到快速计算。
反正我不会。
T4
建树遍历,剪枝,不会……
頑張って