noip模拟44
A. Emotional Flutter
自己乱搞搞了\(50pts\),以为自己的复杂度是\(O(n)\),但其实已经接近\(O(W)\).
乱搞代码
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll long long int
#define ull unsigned ll
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x);
#define Copy(x,y) memcpy(x,y,sizeof x);
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=5e5+51;
ll Ts,n,m,r,t,cnt,alls,print;
struct I { ll l,r,len,col; } p[N];
set<pair<ll,ll> > s;
inline void Pre(){
s.clear();
for(re i=0;i<=n+1;++i) p[i].l=0,p[i].r=0,p[i].col=0,p[i].len=0;
alls=0,cnt=0,print=0;
return ;
}
inline void Init(){
r=read(),t=read(),n=read(); ll temp=r-1,flag;
p[1].l=1; p[0].col=1; flag=((n&1)^1);
if(flag) --n;
for(re i=1;i<=n;++i){
temp+=read(); if(temp<=0) { temp+=r-1; continue; }
if(p[cnt].col!=((i&1)^1)) ++cnt;
p[cnt].len+=temp,p[cnt].col=(i&1)^1;
// if(p[cnt].col) p[cnt].len%=t;
p[cnt].r=p[cnt].l+p[cnt].len-1,p[cnt+1].l=p[cnt].r+1;
if(i&1) temp=1-r; else temp=r-1;
}
if(flag) read();
n=cnt;
for(re i=1;i<=n;++i){
alls+=p[i].len;
if((!p[i].col) and p[i].len>=t){
puts("NIE"); print=1;
}
// cout<<p[i].l<<' '<<p[i].r<<' '<<p[i].len<<' '<<p[i].col<<'\n';
}
// cout<<"\n\n";
return ;
}
inline void Work(){
if(print) return ;
s.insert(mp(0,t));
ll i=1,bz; pair<ll,ll> tmp,temp;
while(i<=n and s.size()){
// cout<<tmp.first<<' '<<tmp.second<<' '<<p[i].l<<' '<<p[i].r<<endl;
if(s.empty()){ puts("NIE"); return ; }
if(!p[i].col) { ++i; continue; }
tmp=*s.begin();
if(tmp.second>alls) { puts("TAK"); return ; }
if(p[i].l>tmp.second) { s.erase(tmp); continue; }
if(p[i].r<tmp.first) { ++i; continue; }
if(p[i].l>=tmp.first and p[i].r<=tmp.second){
bz=(tmp.second-p[i].r)/t+1;
temp.first=p[i].l+t*bz,temp.second=p[i].r+t*bz;
s.insert(temp); ++i;
continue;
}
if(tmp.first>=p[i].l and tmp.second<=p[i].r){
bz=(p[i].r-tmp.second)/t+1;
temp.first=tmp.first+t*bz,temp.second=tmp.second+t*bz;
s.insert(temp); s.erase(tmp);
continue;
}
if(p[i].l<=tmp.first and p[i].r<=tmp.second and p[i].r>=tmp.first){
bz=(tmp.second-p[i].r)/t+1;
temp.first=tmp.first+t*bz,temp.second=p[i].r+t*bz;
s.insert(temp); ++i;
continue;
}
if(tmp.first<=p[i].l and tmp.second<=p[i].r and tmp.second>=p[i].l){
bz=(p[i].r-tmp.second)/t+1;
temp.first=p[i].l+t*bz,temp.second=tmp.second+t*bz;
s.insert(temp); s.erase(tmp);
continue;
}
}
if(s.begin()==s.end()){
if((*s.end()).second>alls) puts("TAK");
else puts("NIE");
}
else{
if((*(--s.end())).second>alls) puts("TAK");
else puts("NIE");
}
return ;
}
signed main(){
Ts=read();
while(Ts--){
Pre();
Init(),Work();
}
return 0;
}
思路来自 MAX_QAQ.
首先把脚的长度累计到黑块上.
对于长度\(\geq k\)的黑块,直接表明本题无解.
起点只有\(k\)个,每个黑块对于对于这些起点均有贡献,可以选择\(mod\ k\)计算.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll long long int
#define ull unsigned ll
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x);
#define Copy(x,y) memcpy(x,y,sizeof x);
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=5e5+51;
ll Ts,n,m,r,t,cnt,alls;
struct I { ll l,r,len,col; } p[N];
pair<ll,ll> e[N];
inline void Pre(){
for(re i=0;i<=n+1;++i) p[i].l=0,p[i].r=0,p[i].col=0,p[i].len=0;
for(re i=0;i<=cnt+1;++i) e[i].first=0,e[i].second=0;
alls=0,cnt=0;
return ;
}
inline void Init(){
r=read(),t=read(),n=read(); ll temp=r-1,flag;
p[1].l=1; p[0].col=1; flag=((n&1)^1);
if(flag) --n;
for(re i=1;i<=n;++i){
temp+=read(); if(temp<=0) { temp+=r-1; continue; }
if(p[cnt].col!=((i&1)^1)) ++cnt;
p[cnt].len+=temp,p[cnt].col=(i&1)^1;
p[cnt].r=p[cnt].l+p[cnt].len-1,p[cnt+1].l=p[cnt].r+1;
if(i&1) temp=1-r; else temp=r-1;
}
if(flag) read(); n=cnt;
}
inline void Work(){
cnt=0; ll l,r;
for(re i=1;i<=n;++i){
if(!p[i].col){
if(p[i].len>=t) { puts("NIE"); return ; }
l=p[i].l%t,r=p[i].r%t;
if(l>r){
e[++cnt].first=0,e[cnt].second=r,
e[++cnt].first=l,e[cnt].second=t-1;
}
else e[++cnt].first=l,e[cnt].second=r;
}
}
sort(e+1,e+1+cnt); r=-1;
// for(re i=1;i<=cnt;++i) cout<<e[i].first<<' '<<e[i].second<<endl;
if(e[1].first!=0) {puts("TAK"); return ;}
for(re i=1;i<=cnt;i++){
if(e[i].first>r+1){
puts("TAK"); return ;
}
else{
r=max(e[i].second,r);
}
}
if(r<t-1) puts("TAK");
else puts("NIE");
return;
}
signed main(){
Ts=read();
while(Ts--){
Pre();
Init(),Work();
}
return 0;
}
B. Medium Counting
这类的方案数题应该一看就是动态规划了.
考虑按位统计即可.
设 \(dp_{i,j,st,en}\) 为转移到第 \(i\) 位,其中 \([st,en]\) 区间内至少是字母 \(j\) 的方案数.
首先有 \(dp\) 转移方程:
我们考虑强制 \([st,k]\) 选择了 \(j\) 字符,
\([k+1,en]\) 至少选择 \([j+1]\) 字符,
那么下一列的 \([st,k]\) 就可以自由选择了,
因为字典序以高位为优先.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll long long int
#define ull unsigned ll
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll mod=990804011;
char s[23];
ll m,n;
ll c[55][23];
ll dp[23][29][55][55];
signed main(){
n=read(); ll tmp;
for(re i=1;i<=n;i++){
scanf("%s",s+1),m=max(m,tmp=strlen(s+1));
for(re j=1;j<=tmp;j++){
c[i][j]=s[j]-'a'+1;
if(s[j]=='?') c[i][j]=27;
}
}
for(re i=1;i<=m;i++){
for(re j=0;j<=27;j++)
for(re k=1;k<=n+1;k++)
for(re h=0;h<k;h++)
dp[i][j][k][h]=1;
}
for(re i=0;i<=n+1;i++) dp[m+1][0][i][i]=1;
for(re i=m;i>=1;i--){
for(re j=26;j>=0;j--){
for(re l=1;l<=n;l++)
for(re st=1,en=st+l-1;en<=n;st++,en++){
dp[i][j][st][en]+=dp[i][j+1][st][en];
for(re k=st;k<=en;k++){
if(c[k][i]!=j and c[k][i]!=27) break;
if(c[k][i]==27 and (!j)) break;
dp[i][j][st][en]=(dp[i][j][st][en]+dp[i+1][0][st][k]*dp[i][j+1][k+1][en]%mod)%mod;
}
}
}
}
printf("%lld\n",dp[1][0][1][n]);
exit(0);
}
C. Huge Counting
可以看成当前 \(x\) 全部变成 \(1\) 的途径的个数其实就是当前的 \(f\) 的值.
考虑进一步简化问题,把途径个数看成方案数,那就是个可重集排列,即\(\dfrac{(\sum_{x_i})!}{\prod\limits(x_i!)}\).
想要求这个东西的奇偶性,发现其实就是求 \(\sum\limits_i({\dfrac{\sum x_j}{2^i}}-\sum\limits {\dfrac{x_j}{2^i}})\).
对于如何求阶乘里面某个质因子 \(p\) 被乘了多少次的方法就比较基础了.
(上面这句话的意思就是,设对于 \(w=n!\),\(w\) 在除以 \(x\) 个 \(p\) 之后和 \(p\) 互质,求 \(x\).)
对于本题来说就是对于每个 \(x\) 在二进制表达下,同一位上最多只有一个 \(1\).
于是数位 \(dp\) 做就行了,注意贡献的最初来源都是 \(x\) 全部等于 \(1\) 的时候,所以注意起点和终点.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:-w;
}
} using namespace BSS;
const ll N=10,M=52,W=1<<10,mod=990804011;
ll m,n,Ts,U;
ll L[N],R[N],num[W];
ll f[M][W],val[N][M];
ll dfs(ll now,ll S){
if(!now) return 1; if(~f[now][S]) return f[now][S];
ll s=0;
for(ll i=1;i<=n;i++){
if( ((S>>i-1)&1) and (!val[i][now]) ) s|=1<<i-1;
}
f[now][S]=dfs(now-1,s);
for(ll i=1;i<=n;i++){
if((s>>i-1)&1) continue;
if((S>>i-1)&1) f[now][S]=(f[now][S]+dfs(now-1,s|1<<i-1))%mod;
else f[now][S]=(f[now][S]+dfs(now-1,s))%mod; // 依旧选这一位为 1,但是没有限制了.
}
return f[now][S];
}
inline void Work(){
Fill(num,0);
ll x,res,cnt,flag; n=read(),U=(1<<n)-1,res=0;
for(ll i=1;i<=n;i++) L[i]=read()-1,R[i]=read()-1;
for(ll i=1;i<=U;i++) num[i]=num[i&(i-1)]+1;
for(ll i=0;i<=U;i++){
flag=0;
for(ll j=1;j<=n;j++){
Fill(val[j],0);
x= (((i>>j-1)&1) ? R[j] : L[j]-1) ,cnt=0;
if(x<0) { flag=1; break; }
for(;x;x>>=1) val[j][++cnt]=(x&1);
}
if(flag) continue;Fill(f,-1);
( (num[U]&1)==(num[i]&1) ) ? res=(res+dfs(50,U))%mod : res=(res-dfs(50,U)+mod)%mod;
}
printf("%lld\n",res);
}
signed main(){
Ts=read();
while(Ts--) Work();
exit(0);
}

浙公网安备 33010602011771号