03-11考试总结
3月11日"考试"总结
你都没考你总结啥
T1
正解
对于01串 \(a\) , 我们在它后面加'0'
并定义其异或序列 : \(b\) , 有 \(b_{i}=a_{i} \oplus a_{i-1}\)
那么 , 每个\(a\)都有唯一的\(b\)与之对应
现在\(a\)的匹配变为\(b\)的匹配 , \(a\)的区间翻转变为\(b\)的两个位置的翻转
考虑怎么匹配 , 发现范围内的\(T\)的长度只有根号种
然后对于一个长度的\(T\) , 我们可以把\(S\)"折起来"计算
复杂度大概是\(n \sqrt n\)级别的 \(O(\)可过\()\)
上代码 :
#include<bits/stdc++.h>
#define MAXN(a) ((max##a)+10)
using namespace std;
const int maxn=200000,maxm=20000000;
struct str{
int *p,tag; str *next;
str(){tag=0,p=NULL,next=NULL;}
~str(){}
};
int n,m,tail,sed;
int s[MAXN(n)];
int t[MAXN(m)];
int p[MAXN(m)];
int cnt[2][MAXN(n)];
int ans[MAXN(m)];
str *beg[MAXN(m)];
inline void init(){
{
char k=getchar();int las=0;
while(k!='a'&&k!='b')k=getchar();
while(k=='a'||k=='b'){
s[++n]=((k=='b')^las);
las=(k=='b'),k=getchar();
}s[++n]=sed=las;
}
scanf("%d",&m);
for(int i=1;i<=m;i=-~i){
char k=getchar();
while(k!='a'&&k!='b')k=getchar();
int len=0;str *now=new str();
now->p=t+tail;now->tag=i;
while(k=='a'||k=='b')
now->p[++len]=(k=='b'),k=getchar();
tail+=len;now->next=beg[len],beg[len]=now;
}
return;
}
inline void pre_work(int len){
memset(cnt,0,sizeof(cnt));
int ed=(n-1)/len*len+1;
for(int i=len+1;i< ed;i++)
cnt[s[i]][(i-1)%len+1]++;
}
inline void calc(str *st,int len){
int &Ans=ans[st->tag];
if(len+1<n){
int ed=(n-1)/len*len+1;
p[1]=st->p[1];
for(int i=2;i<=len;i=-~i)
p[i]=st->p[i]^st->p[i-1];
for(int u=1;u<=len;u=-~u)
Ans+=(s[u]!=p[u]);
p[1]=st->p[1]^st->p[len];
for(int k=1;k<=len;k=-~k)
Ans+=cnt[p[k]^1][k];
for(int u=ed;u<=n-1;u=-~u)
Ans+=(s[u]!=p[u-ed+1]);
Ans+=(st->p[(n-2)%len+1]!=sed);
}
else {
p[1]=st->p[1];
for(int i=2;i<=n-1;i=-~i)
p[i]=st->p[i]^st->p[i-1];
p[n]=st->p[n-1];
for(int u=1;u<=n;u=-~u)
Ans+=(s[u]!=p[u]);
}
return;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
#endif
init();
int cnt=0;
for(int i=1;i<=tail;i=-~i){
if(beg[i]==NULL)continue;
//printf("%d %d %d\n",n,i+1,n%(i+1));
pre_work(i);str *u=beg[i];
while(u!=NULL)
calc(u,i),u=u->next;
}
for(int i=1;i<=m;i=-~i)
printf("%d\n",(ans[i])>>1);
return 0;
}
T2
得分情况 :
预计分数 : 15pts
实际得分 : 15pts
暴力搜就完事了
正解 :
先考虑"已知"从\(1\)到\(n\)花费的时间的期望 , 设为\(l\)
那么有DP式 :
\[f[u][j]=\frac{(\sum min( f[v][j-d[v]],H-(j-d[v])+l) )}{ot[u]}+1
\]
\(min\)里头那坨的意义是 , 你从\(u\)出发到\(v\) , 要么继续从\(v\)走 , 要么从\(v\)返回至起点
而返回至起点后 , 你需要在起点呆 \(H-(j-d[v])\) 的时间回血 , 然后用\(l\)的时间到\(n\)
知道了这个好像没啥用 , 题目要求的就是 \(l\) 的值
但我们发现有了这个后 , \(l\)就可以二分了
因为对于一个二分出的\(l\) , 如果它比\(l_{ans}\)大的话 , 一定有\(f[1][H]< l\)
完事 , 复杂度\(O(n^3*log_2n)\) , 可过
Code :
inline bool check(ldb limt){
for(int i=1;i< n;i=-~i)
for(int j=1;j<=H;j=-~j)
f[i][j]=inf;
for(int u=n-1;u>=1;u--){
for(int j=mx[u]+1;j<=H;j=-~j){
ldb res=0;if(!ot[u])continue;
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
res+=min(f[v][j-d[v]],H-(j-d[v])+limt);
}f[u][j]=(res/(ldb)ot[u])+1;
}
}return f[1][H]< limt;
}
int main(){
r(n),r(m),r(H);
for(int i=1;i<=m;i=-~i){
int r(u),r(v);add(u,v);
}
for(int i=1;i<=n;i=-~i)r(d[i]);
for(int u=1;u<=n;u=-~u)
for(int i=head[u];i;i=e[i].next)
mx[u]=max(mx[u],d[e[i].v]);
ldb l=0,r=2000000,ans=0;
while(l+eps<=r){
ldb mid=(l+r)/2;
if(check(mid))
r=mid-eps,ans=mid;
else l=mid+eps;
}
if(ans>=1000000)puts("-1");
else printf("%.6Lf",ans);
return 0;
}
T3
正解
天上第一的找规律大师lunch发现了规律
我太菜了 , 只能抄他的代码维持生活
所以具体题解看这里
代码(抄的他的) :
#include<bits/stdc++.h>
#define r(a) (a)=read<int>()
#define rl(a) (a)=read<ll>()
#define MAXN(a) ((max##a)+10)
using namespace std;
typedef long long ll;
const int maxk=5000;
const int mod=1e9+7;
namespace Math{
int C[MAXN(k)][MAXN(k)];
inline ll quick_pow(ll a,ll b){
ll ans=1;a%=mod,b%=(mod-1);
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod,b>>=1;
}return ans;
}
inline ll inv(ll a){return quick_pow(a,mod-2);}
inline void init(){
for(int i=0;i<=maxk;i=-~i)
for(int j=0;j<=i;j=-~j)
if(j==0||i==j)C[i][j]=1;
else C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
using Math::C;
using Math::inv;
using Math::quick_pow;
int K,R_,inv_;
ll n,R;
int n_[MAXN(k)];
int s[MAXN(k)];
int S(int k){
if(s[k])return s[k];
int res=1ll*n_[k]*R_%mod,det=0;
for(int i=1;i<=k;i=-~i){
det=1ll*C[k][i]*S(k-i)%mod;
res=(res+((i&1)?-1ll:1ll)*det%mod)%mod;
}return s[k]=1ll*(res%mod+mod)%mod*inv_%mod;
}
template<class T>inline T read();
signed main(){
#ifndef ONLINE_JUDGE
freopen("sword.in","r",stdin);
freopen("sword.out","w",stdout);
#endif
Math::init();n_[0]=1;
int T=read<int>();
while(T--){
r(K),rl(n),rl(R);R_=quick_pow(R,n+1);inv_=inv(R-1);
for(int i=1;i<=K;i=-~i)n_[i]=1ll*n_[i-1]*((n)%mod)%mod;
memset(s,0,sizeof(s));
s[0]=1ll*(R_-(R%mod)+mod)%mod*inv_%mod;
printf("%d\n",S(K));
}
return 0;
}
template<class T>inline T read(){
T sum=0,f=1;char k=getchar();
for(;k< '0'||'9'< k;k=getchar())
if(k=='-')f=-1;
for(;'0'<=k&&k<='9';k=getchar())
sum=(sum<<1)+(sum<<3)+(k^48);
return sum*f;
}