由此开始的记录
从现在开始做的题就往这里放放了,写不写题解,随缘。
这篇博客名来自 Charlotte 大结局的名字。
\(\text{CF149D Coloring Brackets}\)
/*
直接区间 dp,经典的,显然 f[l][r] 表示 [l,r] 的涂色方案。
f[l][r] 没法转移,因为不会判相邻颜色是否相同。
那么记一下两端颜色,因为你 r+1 不可能和 r-1 冲突。
f[l][r][x][y] 表示左端点颜色 x,右端点 y 的方案
为了方便,我们用记忆化搜索,这样可以钦定 l 处是左括号。
如果 l,r 就是匹配的括号,那么显然的 f[l][r][x][y]=sum {f[l+1][r-1][x'][y']}
如果 l,r 并不匹配,那么由于钦定过,我们可以把这个区间换成这样:
(...)(...)(...)...
然后乘法原理,方案数就是
f[ (...) ] * f[ (...)(...)... ]
*/
#include <bits/stdc++.h>
#define rep(i,l,r) for(i=l;i<=r;++i)
using namespace std;
const int N=705,p=1e9+7;
char str[N];
long long f[N][N][3][3];
int ord[N];
inline void dfs(int l,int r)
{
int i,j,a,b,c,d;
if(l+1==r)
{
f[l][r][0][1]=f[l][r][1][0]=f[l][r][0][2]=f[l][r][2][0]=1;
return ;
}
if(ord[l]==r)
{
dfs(l+1,r-1);
rep(i,0,2)rep(j,0,2)
{
if(i!=1)(f[l][r][1][0]+=f[l+1][r-1][i][j])%=p;
if(i!=2)(f[l][r][2][0]+=f[l+1][r-1][i][j])%=p;
if(j!=1)(f[l][r][0][1]+=f[l+1][r-1][i][j])%=p;
if(j!=2)(f[l][r][0][2]+=f[l+1][r-1][i][j])%=p;
}
}else
{
dfs(l,ord[l]);dfs(ord[l]+1,r);
rep(a,0,2)rep(b,0,2)rep(c,0,2)rep(d,0,2)
{
if(b==c && b)break;
(f[l][r][a][d]+=(f[l][ord[l]][a][b]*f[ord[l]+1][r][c][d]%p))%=p;
}
}
return ;
}
int main()
{
int n,i,j;
stack<int> q;
scanf("%s",str+1);n=strlen(str+1);
rep(i,1,n)
{
if(str[i]=='(')q.push(i);
else
{
ord[q.top()]=i;
q.pop();
}
}
dfs(1,n);
long long ret=0;
rep(i,0,2)rep(j,0,2)ret+=f[1][n][i][j];
printf("%lld",ret%p);
return 0;
}
upd on 23-7-10 12:01
\(\text{P4342 [IOI1998] Polygon}\)
/*
断环成链是显然的。断成 2n 之后,f[l][r] 表示合并 [l,r] 的最大值。
先考虑加法,显然 f[l][r]=max{f[l][k]+f[k+1][r]}
对于乘法,考虑到会出现傻逼的负负得正,必须存一个最小值,设这个是 g[l][r]
f[l][r]=max{mxval(l,k,r)}
g[l][r]=min{mnval(l,k,r)}
mxval(l,k,r)=max(f[l][k]*f[k+1][r],f[l][k]*g[k+1][r],g[l][k]*f[k+1][r],g[l][k]*g[k+1][r])
mnval(l,k,r)=min(f[l][k]*f[k+1][r],f[l][k]*g[k+1][r],g[l][k]*f[k+1][r],g[l][k]*g[k+1][r])
*/
#include <bits/stdc++.h>
#define rep(i,l,r) for(i=l;i<=r;++i)
template<class T> inline T max(T head) {
return head;
}
template<class T, typename... Args>inline T max(T head, Args... args) {
T t = max<T>(args...);
return (head > t)?head:t;
}
template<class T> inline T min(T head) {
return head;
}
template<class T, typename... Args>inline T min(T head, Args... args) {
T t = min<T>(args...);
return (head < t)?head:t;
}
const int N=105;
char op[N];
int num[N],f[N][N],g[N][N];
int n,i,le,ret,l,r,k,j,x;
char c;
const int inf=(1<<15);
int main()
{
scanf("%d",&n);
rep(i,1,n)
{
scanf(" %c %d",&c,&x);
op[i]=op[i+n]=c;
num[i]=num[i+n]=x;
}
rep(i,1,2*n)rep(j,1,2*n)f[i][j]=-inf,g[i][j]=inf;
rep(i,1,2*n)f[i][i]=g[i][i]=num[i];
rep(le,2,n)
rep(l,1,2*n-le+1)
{
r=l+le-1;
rep(k,l,r-1)
{
if(op[k+1]=='x')
{
f[l][r]=max(f[l][r],f[l][k]*f[k+1][r],f[l][k]*g[k+1][r],g[l][k]*f[k+1][r],g[l][k]*g[k+1][r]);
g[l][r]=min(g[l][r],f[l][k]*f[k+1][r],f[l][k]*g[k+1][r],g[l][k]*f[k+1][r],g[l][k]*g[k+1][r]);
}else
{
f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]);
g[l][r]=min(g[l][r],g[l][k]+g[k+1][r]);
}
}
// printf("%d %d %d\n",l,r,f[l][r]);
}
rep(i,1,n)ret=max(ret,f[i][i+n-1]);
printf("%d\n",ret);
rep(i,1,n)if(f[i][i+n-1]==ret)
printf("%d ",i);
return 0;
}
upd on 23-7-10 12:44
\(\text{P3052 [USACO12MAR] Cows in a Skyscraper G}\)
/*
直接模拟退火啊。
*/
#include <bits/stdc++.h>
#define rep(i,l,r) for(i=l;i<=r;++i)
const int N=20;
int a[N];
int n,W,x,y,m,i;
using namespace std;
const double bT=1e5, eT=1e-3, derta=0.97;
inline int cost()
{
int i, pre=0, ret=0;
rep(i,1,n)
{
if(pre+a[i]>W)
{
++ret;
pre=a[i];
}else
pre+=a[i];
}
return ret+(pre>0);
}
inline int SA()
{
int ans=cost(), mid;
for(double T=bT; T>=eT; T*=derta)
{
x=rand()%n+1;y=rand()%n+1;
swap(a[x],a[y]);
mid=cost();
if(mid<ans)
ans=mid;
else if(exp((mid-ans)/T)<1.*rand()/RAND_MAX)
swap(a[x],a[y]);
}
return ans;;
}
int main()
{
srand(8925);
scanf("%d %d",&n,&W);
auto beginning=clock();
rep(i,1,n)scanf("%d",a+i);
int ret=SA();
while((clock()-beginning)*1.0/CLOCKS_PER_SEC <=0.9)ret=min(ret,SA());
printf("%d",ret);
return 0;
}
upd on 23-7-10 15:15
\(\text{CF629C Famil Door and Brackets}\)
/*
设 f[i][j] 表示前 i 个,cnt[(]-cnt[)] 的数量为 j 的方案数。
这个可以做出 P,Q 的样子啊。
接下来枚举 P 的长度,lp+lq+ls=n
然后枚举 P 的 cnt[(]-cnt[)] 的值。
需要满足 dertap+dertaq+dertas=0
直接乘法原理即可。
比如枚举出 p[lp][dertap],那么 lq=n-ls-lp, dertaq=-dertas-dertap
*/
#include <bits/stdc++.h>
#define int long long
#define rep(i,l,r) for(i=l;i<=r;++i)
using namespace std;
const int N=100005,p=1e9+7;
int f[2015][2015];
char str[N];
int i,j,x,mrex=p,n,m,ret;
inline void pre()
{
f[0][0]=1;
rep(i,1,2005)
{
f[i][0]=f[i-1][1];
rep(j,1,i)f[i][j]=(f[i-1][j-1]+f[i-1][j+1])%p;//,printf("%d %d %d\n",i,j,f[i][j]);
}
return ;
}
inline int gmax()
{
rep(i,1,m)
{
if(str[i]=='(')++x;else --x;
mrex=min(mrex,x);
}
return mrex;
}
inline int solve()
{
pre();
gmax();
// if(n>2000)printf("%d %d\n",x,mrex);
rep(i,0,n-m)
rep(j,0,i)
{
if(j>=-mrex && j+x<=n-m-i)
{
// printf("%d %d %d %d %d %d\n",i,j,f[i][j],n-m-i,j+x,f[n-m-i][j+x]);
(ret+=(1ll*f[i][j]*f[n-m-i][j+x])%p)%=p;
}
// printf("%d %d %d\n", i, j, ret);
}
printf("%lld",ret);
return 0;
}
signed main()
{
scanf("%d %d %s", &n, &m, str+1);
solve();
return 0;
}
upd on 23-7-11 7:00
\(\text{P8675 [蓝桥杯 2018 国 B] 搭积木}\)
这题我随便写了个题解,可以去看看然后爆 down 我。
upd on 23-7-12 13:01
\(\text{P6218 [USACO06NOV] Round Numbers S}\)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(i=l;i<=r;++i)
int f[75][75],l,r,i,j,cnt,lg[55];
inline int dp(bool limit,bool lzero,int dep,int derta)
{
if(dep==0)return derta>=30;
else if(!limit && !lzero && f[dep][derta]!=-1)return f[dep][derta];
else
{
int ret=0,i,nxt=limit?lg[dep]:1;
rep(i,0,nxt)
{
ret+=dp(limit&&(i==lg[dep]),lzero&&(i==0),dep-1,derta+(i==1?-1:(lzero?0:1)));
}
if(!limit && !lzero)f[dep][derta]=ret;
return ret;
}
}
int solve(int x)
{
cnt=0;while(x)
{
lg[++cnt]=x&1;
x>>=1;
}
return dp(1,1,cnt,30);
}
int main()
{
int l,r;scanf("%d %d",&l,&r);
rep(i,0,31)rep(j,0,61)f[i][j]=-1;
printf("%d\n",solve(r)-solve(l-1));
return 0;
}
upd on 23-7-13 23:43
\(\text{UVA1640 The Counting Problem}\)
双倍经验 \(\text{ SP3928 MDIGITS - Counting Digits}\)。
#include <bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(i=l;i<=r;++i)
int f[15][15],lg[15];
int ret;
inline int dp(bool limit,bool lzero,int dep,int fl,int sum)
{
// printf("%d %d %d %d %d\n",limit,lzero,dep,fl,sum);
if(dep==0)
return sum;
if(!limit && !lzero && f[dep][sum]!=-1)return f[dep][sum];
int ret=0,i,nxt=limit?lg[dep]:9;
rep(i,0,nxt)ret+=dp(limit&&(i==lg[dep]),lzero&&(i==0),dep-1,fl,sum+(!(lzero&&(i==0))&&i==fl));//,printf("%d\n",i);//,printf("%d\n",ret);
if(!limit && !lzero)f[dep][sum]=ret;
return ret;
}
inline int solve(int v,int fl)
{int cnt,i,j;
rep(i,0,12)rep(j,0,12)f[i][j]=-1;
cnt=0;while(v)
{
lg[++cnt]=v%10;
v/=10;
}
return dp(1,1,cnt,fl,0);
}
int main()
{int i,j,l,r;
// printf("%d\n",solve(10,2));
while(cin>>l>>r && (l||r))
{if(l>r)swap(l,r);
rep(i,0,8)printf("%d ",solve(r,i)-solve(l-1,i));
printf("%d\n",solve(r,9)-solve(l-1,9));
}
return 0;
}
upd on 23-7-14 0:15
\(\text{CF855E Salazar Slytherin's Locket}\)
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
ll f[15][70][1<<12];
ll lg[70];
int cnt,t,b;
ll l,r;
inline ll dp(bool limit,bool lzero,int dep,int sta,int b)
{
if(dep==0)return sta==0;
else if(!limit && !lzero && f[b][dep][sta]!=-1)return f[b][dep][sta];
else
{
ll ret=0;
int i,nxt=limit?lg[dep]:b-1;
for(i=0;i<=nxt;++i)
ret+=dp(limit&&(i==nxt),lzero&&(i==0),dep-1,(lzero&&i==0)?0:(sta^(1<<i)),b);
if(!limit && !lzero)f[b][dep][sta]=ret;
return ret;
}
}
inline ll solve(ll x,int b)
{
cnt=0;while(x)
{
lg[++cnt]=x%b;
x/=b;
}
return dp(1,1,cnt,0,b);
}
int main()
{
memset(f,-1,sizeof f);
scanf("%d",&t);
while(t--)
{
scanf("%d %lld %lld",&b,&l,&r);
printf("%lld\n",solve(r,b)-solve(l-1,b));
}
}
upd on 23-7-14 12:03
SP10606 BALNUM - Balanced Numbers
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
int f[20][1<<10][1<<10],lg[20];
int cnt;ll l,r;
inline bool check(int x,int y)
{
for(int i=0;i<10;++i)
if((x&(1<<i)) && ((i&1)==((y>>i)&1)))
return false;
return true;
}
inline ll dp(int limit,int lzero,int dep,int sta1,int sta2)
{
if(dep==0)return check(sta1,sta2);
else if(!limit && !lzero && f[dep][sta1][sta2]!=-1)return f[dep][sta1][sta2];
else
{
ll ret=0;
int i,nxt=limit?lg[dep]:9;
for(i=0;i<=nxt;++i)
ret+=dp(limit&&(i==nxt),lzero&&(i==0),dep-1,(lzero&&(i==0))?0:(sta1|(1<<i)),(lzero&&(i==0))?0:(sta2^(1<<i)));
if(!limit && !lzero)f[dep][sta1][sta2]=ret;
return ret;
}
}
inline ll solve(ll x)
{
cnt=0;while(x)
{
lg[++cnt]=x%10;
x/=10;
}
return dp(1,1,cnt,0,0);
}
int main()
{
memset(f,-1,sizeof f);
int t;scanf("%d",&t);
while(t--)
{
scanf("%lld %lld",&l,&r);
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}
upd on 23-7-14 12:25
P3810 【模板】三维偏序(陌上花开)
#include <bits/stdc++.h>
#define rep(i,l,r) for(i=l;i<=r;++i)
using namespace std;
const int N=1e5+5,V=2e5+5;
int ret[N];
int n,m,t,i,j,k;
class Eti
{
public:
int a,b,c,cnt,res;
inline const bool operator!=(const Eti &other)const
{
return a!=other.a || b!=other.b || c!=other.c;
}
};
Eti e[N],ue[N];
class bit
{
public:
int tr[V];
inline void add(int x,int p)
{
while(x<=k)
{
tr[x]+=p;
x+=(x&-x);
}
}
inline int ask(int x)
{
int ret=0;
while(x)
{
ret+=tr[x];
x-=(x&-x);
}
return ret;
}
}bit;
using cE=const Eti &;
inline const bool compareA(cE x,cE y)
{
return x.a!=y.a?x.a<y.a:(x.b!=y.b?x.b<y.b:x.c<y.c);
}
inline const bool compareB(cE x,cE y)
{
return x.b!=y.b?x.b<y.b:x.c<y.c;
}
inline void cdq(int l,int r)
{
if(l==r) return ;
int mid=l+r>>1;
cdq(l,mid);cdq(mid+1,r);
sort(ue+l,ue+mid+1,compareB);
sort(ue+mid+1,ue+r+1,compareB);
int i=l,j=mid+1;
while(j<=r)
{
while(i<=mid && ue[i].b<=ue[j].b)
{
bit.add(ue[i].c,ue[i].cnt);
++i;
}
ue[j].res+=bit.ask(ue[j].c);
++j;
}
int k;
rep(k,l,i-1)bit.add(ue[k].c,-ue[k].cnt);
}
int main()
{
int i;
scanf("%d %d",&n,&k);
rep(i,1,n)scanf("%d %d %d",&e[i].a,&e[i].b,&e[i].c);
sort(e+1,e+n+1,compareA);
rep(i,1,n)
{
++t;
if(e[i]!=e[i+1])
{
++m;
ue[m]=e[i];
ue[m].cnt=t;
t=0;
}
}
cdq(1,m);
rep(i,1,n)ret[ue[i].res+ue[i].cnt-1]+=ue[i].cnt;
rep(i,0,n-1)printf("%d\n",ret[i]);
return 0;
}
upd on 23-7-14 23:41