A 构造
cpp
void solve(){
string s;cin>>s;
int n=s.size();
if(n<5)rno;//#define rno return cout<<"No"<<endl,void()
s=' '+s;
int hd=0,fg=0;
vector<int>t,h;
vector<pii>ans;
reforr(i,1,n){
if(fg==0){
hd+=(s[i]=='>');//hd匹配头上的>>>
if(s[i]=='-'){
if(hd<3)rno;
fg=1;
}
}else if(s[i]=='>')t.push_back(i);
}
//s[1]一定要是> 否则会有->-->>>的不合法情况
if(s[1]=='-'||fg==0||t.size()==0){
rno;//#define rno return cout<<"No"<<endl,void()
}
int bg=n-hd+3;
reforr(i,bg,n)h.push_back(i);//头顶从大到小
sort(t.begin(),t.end());//尾巴从小到大
if(h.size()>t.size())swap(h,t);
int sz=h.size(),pid=0;
for(auto i:t){
ans.push_back({min(i,h[pid]),max(i,h[pid])});
if(pid+1<sz)pid++;
}
cout<<"Yes "<<ans.size()<<endl;
for(auto x:ans){
cout<<x.fir<<' '<<x.sec-x.fir+1<<endl;
}
}
G 位运算 思维
只有三种运算x&y x^y x|y
每一位上01状态不同会有不同的结果,所以把xy的每一位组合在一起看结果能得到什么样的数
cpp
void solve(){
int n;cin>>n;
set<int>s;
vector<int>a(n+1);
forr(i,1,n)cin>>a[i];
//废案 一开始想到了暴力bfs
// forr(i,2,n-1){
// s.insert(a[i+1]&a[i]);
// s.insert(a[i+1]|a[i]);
// s.insert(a[i+1]^a[i]);
// }
s.insert(0);
forr(i,1,n-1){
//b11结果是x&y的该位结果 b10+b01是^ b10+b11+b01是|
int b11,b10,b01;b11=b01=b10=0;
//计算每一位情况
reforr(j,0,31){
int bnow=a[i]&(1<<j),bnxt=a[i+1]&(1<<j);
if(bnow&&bnxt)b11|=bnow;
else if(bnow)b10|=bnow;
else if(bnxt)b01|=bnxt;
}
//x=now y=nxt
//b10:x^y&x->(b10+b01-b01) b01:x^y&y
//b10+b11:x b01+b11:y
vector<int>tp={b11,b10+b01,b11+b01+b10,b10,b01,b10+b11,b01+b11};
for(auto t:tp)s.insert(t);
}
cout<<s.size()<<endl;
}
I 线段树 gcd
把数组分成长度为k的等长的非递减段(最后一段可以<=k),最后求合法k的个数
最大的k就是每个非递减段长度的gcd
- 这里可以直接用分段处的下标 因为gcd(a,b-a)=gcd(a,b)
如 2 3 |1 4 5 7 | 8 9,k=2
分段下标i=2 6 8
每个等长非递减段又可以分,分解成k的因数长
有多个询问,使用线段树优化
cpp
const int N=2e5+4;
struct node
{ //区间 值
int l,r,val;
};
struct segmentr{
node tr[N<<2];
void build(int pos,int l,int r){
tr[pos]={l,r,0};
if(l!=r){
int mid=(l+r)>>1;
build(pos<<1,l,mid);
build(pos<<1|1,mid+1,r);
}
}
void pushup(int pos){
tr[pos].val=__gcd(tr[pos<<1].val,tr[pos<<1|1].val);//更新大区间的gcd
}
void modify(int pos,int aim,int val){
if(tr[pos].l==tr[pos].r){tr[pos].val=val;return;}
int mid=(tr[pos].l+tr[pos].r)>>1;
if(mid>=aim)modify(pos<<1,aim,val);
else modify(pos<<1|1,aim,val);
pushup(pos);
}
}t;
int cnt[N];//因数个数
//直接对分界点位置i进行gcd 因为gcd(a,b,c)=gcd(a,b-a,c-b) 线性组合后gcd不变
void solve(){
int n,q;cin>>n>>q;
t.build(1,1,n);
vector<int>a(n+2);
forr(i,1,n){
cin>>a[i];
}
a[n+1]=0;
forr(i,1,n-1){//最后一个点不必加进去 因为长度不一定是k
if(a[i]>a[i+1]){
t.modify(1,i,i);//记录递增段最后的一个点 递减分界点
}
else t.modify(1,i,0);
}
int ans=t.tr[1].val;//所有断点下标的gcd
if(ans==0)cout<<n<<endl;//a全为0 最长段是n
else cout<<cnt[ans]<<endl;//注意最后要输出合规长度的数量
forr(i,1,q){
int p,v;cin>>p>>v;
a[p]=v;
if(p>1&&a[p-1]>a[p])t.modify(1,p-1,p-1);
else t.modify(1,p-1,0);
if(p<n&&a[p+1]<a[p])t.modify(1,p,p);
else t.modify(1,p,0);
int ans=t.tr[1].val;
if(ans==0)cout<<n<<endl;
else cout<<cnt[ans]<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
forr(i,1,N-3){
for(int j=1;i*j<=N-3;j++)cnt[i*j]++;
}
int _=1;
cin>>_;
while (_--)
{
solve();
}
return 0;
}
B dp计情况数 三位前缀和优化
cpp
const int N=304,mod=1e9+7;
//a b c数量有制约关系 可以优化一维c
int nd[N],dp[N][N][N][4];//dp[i][j][k][p] i位置 用j个a k个b 有多少情况
int sum[N][N][N];
void solve(){
int n,q;cin>>n>>q;
string s;
cin>>s;s=' '+s;
forr(i,1,n){
nd[i]=nd[i-1]+(s[i]=='?');//nd记录i位置之前需要多少
}
if(s[1]=='?')dp[1][1][0][0]=dp[1][0][1][1]=dp[1][0][0][2]=1;
else dp[1][0][0][s[1]-'a']=1;
//dp计算情况数
forr(i,2,n){
forr(a,0,nd[i]){
for(int b=0;b+a<=nd[i];b++){
int c=nd[i]-a-b;
forr(p,0,2){
if(s[i]=='?'){
if(a&&p!=0)(dp[i][a][b][0]+=dp[i-1][a-1][b][p])%=mod;
if(b&&p!=1)(dp[i][a][b][1]+=dp[i-1][a][b-1][p])%=mod;
if(c&&p!=2)(dp[i][a][b][2]+=dp[i-1][a][b][p])%=mod;
}else{
if(p==s[i]-'a')continue;
(dp[i][a][b][s[i]-'a']+=dp[i-1][a][b][p])%=mod;
}
}
}
}
}
//sum求三维前缀和 对之后a b c的询问优化
forr(a,0,300){
forr(b,0,300){
forr(c,max(nd[n]-a-b,0ll),300){
if(a+b+c<=nd[n])(sum[a][b][c]+=((dp[n][a][b][0]+dp[n][a][b][1])%mod+dp[n][a][b][2]))%=mod;
if(a)(sum[a][b][c]+=sum[a-1][b][c])%=mod;
if(b)(sum[a][b][c]+=sum[a][b-1][c])%=mod;
if(c)(sum[a][b][c]+=sum[a][b][c-1])%=mod;
if(b&&c)(sum[a][b][c]+=mod-sum[a][b-1][c-1])%=mod;
if(a&&c)(sum[a][b][c]+=mod-sum[a-1][b][c-1])%=mod;
if(a&&b)(sum[a][b][c]+=mod-sum[a-1][b-1][c])%=mod;
if(a&&b&&c)(sum[a][b][c]+=sum[a-1][b-1][c-1])%=mod;
}
}
}
/*
三维前缀和
S(x, y, z) = a(x, y, z)
+ S(x, y, z-1) + S(x, y-1, z) + S(x-1, y, z)
- S(x, y-1, z-1) - S(x-1, y, z-1) - S(x-1, y-1, z)
+ S(x-1, y-1, z-1)
*/
forr(i,1,q){
int a,b,c;cin>>a>>b>>c;
cout<<sum[a][b][c]<<endl;
}
}