10.7 考试
T1
对于每一个G,最小耗时是她前面B的个数,但是当G连在一起时,就有可能把她卡住
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=1000006;
char s[N];
int n;
int main(){
scanf("%s",s);
n=strlen(s);
int ans=0,con=0;
for(int i=0;i<n;++i)
{
if(s[i]=='B')
++con;
else
ans=max(ans+1,con);
}
cout<<ans;
}
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <ctime>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=1000006;
char s[N];
int n;
int pre[N],nxt[N];
//bool flag[N];
int work()
{
int now=1;
while(now<=n&&s[now]!='G')++now;
if(s[now]=='B')
{
nxt[0]=n+1;
pre[n+1]=0;
}
else
{
nxt[0]=now;
pre[now]=0;
for(int i=now;i<=n;)
{
now=i;
while(now<=n&&s[now]=='G')++now;
while(now<=n&&s[now]=='B')++now;
pre[now]=i;
nxt[i]=now;
i=now;
}
}
/*for(int i=nxt[0];i<=n;i=nxt[i])
printf("i=%d\n",i);*/
//for(int i=0;i<=n+1;++i)
// printf("i=%d %d %d\n",i,pre[i],nxt[i]);
int t=0,swif;
while(1)
{
++t;
swif=0;
for(int i=nxt[0];i<=n;i=nxt[i])
{
//printf("i=%d\n",i);
//system("pause");
if(i==1)
continue;
swif=1;
nxt[pre[i]]=i-1;
pre[nxt[i]]=i-1;
pre[i-1]=pre[i];
nxt[i-1]=nxt[i];
s[i]='B';
s[i-1]='G';
if(i-2<1||s[i-2]=='B')
{
if(i+1<=n&&s[i+1]=='G')
{
pre[nxt[i]]=i+1;
nxt[i-1]=i+1;
pre[i+1]=i-1;
nxt[i+1]=nxt[i];
}
}
else
{
pre[nxt[i]]=pre[i];
nxt[pre[i]]=nxt[i];
if(i+1<=n&&s[i+1]=='G')
{
pre[nxt[i]]=i+1;
nxt[pre[i]]=i+1;
pre[i+1]=pre[i];
nxt[i+1]=nxt[i];
}
}
}
if(!swif)
return t-1;
//for(int i=0;i<=n+1;++i)
// printf("i=%d %d %d\n",i,pre[i],nxt[i]);
/*for(int i=1;i<=n;++i)
printf("%c",s[i]);
printf("\n");*/
}
}
int main(){
//freopen("T1.in","r",stdin);
//freopen("T111.out","w",stdout);
//freopen("line.in","r",stdin);
//freopen("line.out","w",stdout);
scanf("%s",s);
n=strlen(s);
for(int i=n;i>=1;--i)
s[i]=s[i-1];
s[0]=0;
cout<<work();
//printf("\n%d\n",clock());
}
/*nxt[0]=now;
pre[now]=0;
for(int i=now;i<=n;)
{
now=i;
while(s[now]=='G'&&now<=n)++now;--now;
if(s[now]=='B')
{
nxt[i]=n+1;
pre[n+1]=i;
}
else
if(now!=i)
{
pre[now]=i;
nxt[i]=now;
}
i=now;
++now;
while(now<=n&&s[now]=='B')++now;
pre[now]=i;
nxt[i]=now;
i=now;
}*/
T2
60分dp:
f[i][j][k] 前i位,最长长度==j,最后一个字符是k
$$f[i][j][k]=\sum_{l=i-j}^{i-1}\sum_{p!=k}^mdp[l][j][p]*sum[l+1][j][k]+\sum_{h=1}^{j-1}\sum_{p!=k}dp[i-j][h][p]*sum[i-j+1][i][k]$$
其中sum是从i到j字符全是k的概率,$O(n^2m)$求出
正解有两个,一个是$O(n^2m^2)$的,一个是$O(n^2m)$的
后一个更好理解,也更快
dp[i][j][k] 到了第i个位置,最长长度<=j,最后一个字符是k 的概率
f[i][j] 到了第i个位置,最长长度<=j 的概率 (其实就是把dp的第三维去掉了)
$$dp[i][j][k]=f[i-1][j]*sum[i][i][k]-(f[i-j-1][j]-dp[i-j-1][j][k])*sum[i-j][i][k]$$
其实就是把所有情况都先转移过来,然后去掉不合法的情况
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#define dd double
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int n,m;
dd p[1006][16];
dd s[1006][1006][16];
dd f[1006][1006],dp[1006][1006][16];
void chu()
{
for(int i=1;i<=m;++i)
p[0][i]=1.0;
for(int k=1;k<=m;++k)
for(int i=1;i<=n;++i)
{
s[i][i][k]=p[i][k];
for(int j=i+1;j<=n;++j)
s[i][j][k]=s[i][j-1][k]*p[j][k];
}
}
dd work()
{
dd ans=0;
for(int i=0;i<=n;++i)
f[0][i]=1;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
for(int k=1;k<=m;++k)
{
//printf("i=%d j=%d k=%d\n",i,j,k);
dp[i][j][k]=f[i-1][j]*s[i][i][k];
if(i-j-1>=0)
dp[i][j][k]-=(f[i-j-1][j]-dp[i-j-1][j][k])*s[i-j][i][k];
f[i][j]+=dp[i][j][k];
}
for(int j=1;j<=n;++j)
ans+=(f[n][j]-f[n][j-1])*j;
return ans;
}
int main(){
//freopen("1.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%lf",&p[i][j]);
chu();
printf("%.5lf",work());
}
T3
设B=sqrt(n)
把集合大小>B的定为重集合,<=B的定为轻集合
处理一个数组cnt[][]记录每一个集合与重集合的交集个数,这个可以$O(n\sqrt{n})$处理
每一个重集合维护 sum、add,分别表示重集合不加标记的值和标记的值
然后插入、询问分4个操作:
1.轻集合add,暴力加轻集合内的元素,再更新与之有交集的重集合的sum
2.重集合add,直接标记
3.轻集合qq,直接暴力统计+与之有交集的重集合标记*cnt[i][j]
4.重集合qq,sum+与之有交集的重集合标记*cnt[i][j]
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=100006;
int n,m,Q;
int B;
ll a[N];
vector<int> ji[N],dian[N];
int num[N];
int zhong[N],con,dui[N];
int cnt[N][336];
ll biao[N],sum[N];
void chu()
{
int temp,s1,s2;
for(int i=1;i<=m;++i)
{
for(int j=0;j<num[i];++j)
{
s1=dian[ji[i][j]].size();
for(int k=0;k<s1;++k)
++cnt[i][ dian[ji[i][j]][k] ];
}
}
}
ll qq(int x)
{
ll ans=0;
if(num[x]>B)
{
ans+=sum[dui[x]];
for(int i=1;i<=con;++i)
ans+=cnt[x][i]*biao[i];
return ans;
}
for(int i=0;i<num[x];++i)
ans+=a[ji[x][i]];
for(int i=1;i<=con;++i)
ans+=cnt[x][i]*biao[i];
return ans;
}
void add(int x,int val)
{
if(num[x]>B)
{
biao[dui[x]]+=val;
return ;
}
for(int i=0;i<num[x];++i)
a[ji[x][i]]+=val;
for(int i=1;i<=con;++i)
sum[i]+=cnt[x][i]*val;
}
int main(){
scanf("%d%d%d",&n,&m,&Q);
B=sqrt(n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
int tin1,tin2;
for(int i=1;i<=m;++i)
{
scanf("%d",&num[i]);
if(num[i]>B)
{
zhong[++con]=i;
dui[i]=con;
}
for(int j=1;j<=num[i];++j)
{
scanf("%d",&tin1);
ji[i].push_back(tin1);
if(zhong[con]==i)
{
dian[tin1].push_back(con);
sum[con]+=a[tin1];
}
}
}
chu();
int op;
for(int i=1;i<=Q;++i)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d",&tin1);
printf("%lld\n",qq(tin1));
}
else
{
scanf("%d%d",&tin1,&tin2);
add(tin1,tin2);
}
}
}
总结:
第一题是思考题,但是我一意孤行的认为跟 clock 那个题一样 打了链表...
对于2.3题,当然要打暴力了....
但是最近总是想不出来...