观察样例发现大概是 \(gcd(a,b) \neq 1\)的时候是无限,试了下A了 面向样例编程ios
除了cf应该不能这么意识流编程 正赛的时候这一两分钟也没那么重要c++
中等复杂的模拟题,但我写的时候一直wa,换了三种策略都没成,后来在广神的帮助下找到了是输出字符数组没有加结束符致使每次多样例的输出就会多不少东西,这种神奇的bug我还真是第一次遇到,记录一下。算法
#include <bits/stdc++.h> using namespace std; char l[10001],out[10001]; int main(){ //freopen("test.in","r",stdin); //freopen("test.out","w",stdout); int t,a,b,c,n,ans; cin>>t; while(t--){ cin>>n; cin>>a>>b>>c; cin>>l; for(int i=0;i<n;i++){ out[i]='0'; } ans=0; for(int i=0;i<n;i++){ if(l[i]=='R' && b>0){b--;ans++;out[i]='P';} if(l[i]=='P' && c>0){c--;ans++;out[i]='S';} if(l[i]=='S' && a>0){a--;ans++;out[i]='R';} } //cout<<out<<endl; for(int i=0;i<n;i++){ if(out[i]=='0'){ if(l[i]=='R') if(a>0){a--;out[i]='R';} else {c--;out[i]='S';} if(l[i]=='S') if(c>0){c--;out[i]='S';} else {b--;out[i]='P';} if(l[i]=='P') if(b>0){b--;out[i]='P';} else {a--;out[i]='R';} } } if(n%2==0 && ans>=(n/2)){ cout<<"YES"<<endl; for(int i=0;i<n;i++)printf("%c",out[i]); cout<<endl; } else if(n%2==1 && ans>(n/2)){ cout<<"YES"<<endl; for(int i=0;i<n;i++)printf("%c",out[i]); cout<<endl; } else cout<<"NO"<<endl; } return 0; }
总结下就是算法没有问题可是wa得很靠前的时候,仍是要注意下像输入输出啊预处理啊这种东西,想起来秦皇岛哪一个暴力dp也是由于预处理的字符表有问题疯狂wa。spring
规则1:字符串中的m会被写成nn,w写成uu编程
输入为原字符串通过规则1转化而来的字符串,问原字符串有多少种可能。数组
1.若给定串中有m或w,则出错,ans=0spa
2.分块.net
将连续的(大于等于2个)的u/n连续子串分开,每一个长度为 \(l1,l2,l3...lm\) 容易发现对于每一个子串,rest
ans[li]=ans[li-1]-ans[i-2];
斐波那契啊这是!那这下就解决了code
#include<bits/stdc++.h> using namespace std; const long long mod = 1000000007; long long fib[201111],pre[2000011]; char a[200011]; int main(){ fib[0]=1;fib[1]=1; for(int i=2;i<100212;i++){fib[i]=(fib[i-1]+fib[i-2])%mod;} cin>>a; long long len=strlen(a),pos=0,num=0,ans=1; for(int i=0;i<len;i++)if(a[i]=='w' || a[i]=='m'){cout<<'0'<<endl;return 0;} while(pos<len){ if(a[pos]=='u' && a[pos+1]=='u'){ while(a[pos]=='u' && pos<len){ pos++; pre[num]++; } num++; } else if(a[pos]=='n' && a[pos+1]=='n'){ while(a[pos]=='n' && pos<len){ pos++; pre[num]++; } num++; } else pos++; } if(num==0){cout<<1<<endl;return 0;} for(int i=0;i<num;i++)ans = (long long) ans * fib[ pre[i]] % mod; cout<<ans<<endl; return 0; }
作的时候并无什么很好的思路果真仍是本身菜qaq集训室有人吼了一句最小生成树,可是想了想并不知道解决出在哪些点创建电厂的这个前置问题;再加上b题浪费了过于多的时间,被迫放弃这个D。补题的时候看到一个聚聚写的博客简简单单提了一句超级根,一语点醒梦中人;只要创建超级源点到每一个点的权值做为c[i],就能够巧妙地使创建电站和链接电网的价值转化为一个问题,从而跑个最小生成树就ok了。其实超级源点这个东西之前用的仍是不少的,我甚至还给zz和瓜神说过这个玩意儿,此次仍是没想到有点不该该。
#include<bits/stdc++.h> #define ll long long #define maxn 2005 using namespace std; int n; ll X[maxn],Y[maxn],c[maxn],k[maxn]; struct edge { int u,v; ll w; edge(int U=0,int V=0,ll W=0):u(U),v(V),w(W){} }e[maxn*maxn]; int fa[maxn]; bool operator < (edge A,edge B){return A.w<B.w;} int find(int x) { if(fa[x]==x)return x; return fa[x]=find(fa[x]); } vector<int> A; vector< pair<int,int> >B; int main() { scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%I64d%I64d",&X[i],&Y[i]); for(int i=1;i<=n;++i)scanf("%I64d",&c[i]); for(int i=1;i<=n;++i)scanf("%I64d",&k[i]); int cnt=0; for(int i=0;i<=n;++i)fa[i]=i; for(int i=1;i<=n;++i)e[++cnt]=edge(0,i,c[i]); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j)if(i!=j)e[++cnt]=edge(i,j,(k[i]+k[j])*(abs(X[i]-X[j])+abs(Y[i]-Y[j]))); sort(e+1,e+cnt+1); ll ans=0; for(int i=1;i<=cnt;++i) { int u=e[i].u,v=e[i].v; if(find(u)==find(v))continue; fa[find(v)]=find(u); ans+=e[i].w; if(!u)A.push_back(v); else B.push_back(make_pair(u,v)); } printf("%I64d\n",ans); printf("%d\n",A.size()); for(auto p: A)printf("%d ",p); puts(""); printf("%d\n",B.size()); for(auto p: B)printf("%d %d\n",p.first,p.second); }
几率dp,待补,这个当成专题叭,据说是道不难的几率dp
我的仍是比较怕这种创建在数位运算上的题的,多是对这些不太敏感不怎么能分析的出来。
若是 \(x+y=x⊕y\) 则 $x∗y=0 $
若是想数位dp的话,这实际上是道挺板的题,牛客多校有比这个可贵多的,有机会仍是多补一点叭
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll dp[40][2][2][2][2]; int abit[33],bbit[33]; ll dfs(int len,int lim1,int lim2,int z1,int z2){ if(len==-1)return 1; if(dp[len][lim1][lim2][z1][z2]!=-1)return dp[len][lim1][lim2][z1][z2]; ll ans=0; int up1=lim1?abit[len]:1; int up2=lim2?bbit[len]:1; for(int i=0;i<=up1;i++){ for(int j=0;j<=up2;j++){ if((i+j)==(i^j)){ ans+=dfs(len-1,lim1&&i==up1,lim2&&j==up2,z1||i!=0,z2||j!=0); } } } dp[len][lim1][lim2][z1][z2]=ans; return ans; } ll solve(ll a,ll b){ memset(dp,-1, sizeof(dp)); for(int i=30;i>=0;i--){ abit[i]=a>>i&1; bbit[i]=b>>i&1; } dfs(30,1,1,0,0); } ll t,l,r; int main(){ ios::sync_with_stdio(false); cin>>t; ll a,b,c; while (t--){ cin>>l>>r; if(l==0){ a=slove(r,r); cout<<a<<endl; continue; } a=solve(r,r); b=solve(l-1,l-1); c=solve(l-1,r); cout<<a+b-c-c<<endl; } }
这道题也能够直接按题解里面的递推式来算,看了题解仍是大脑空空,头挺大的
有两个关键的式子:
\[ f(0,r)=2r−1+f(1,r)\\f(2l,2r)=3⋅f(l,r) \]
有了这两个死也想不到的式子,就能够开始愉快的递推了
\[ f(l+1,r)=f(l,r)−2⋅(g(l,r)−g(l,l))\\f(l,r)=f(l+1,r)+2⋅(g(l,r)−g(l,l))\\ \]
\[ \\ f(l,r−1)=f(l,r)−2⋅(g(r−1,r)−g(r−1,l)\\ f(l,r)=f(l,r−1)+2⋅(g(r−1,r)−g(r−1,l)) \]
贴个标程:
#include<bits/stdc++.h> using namespace std; int f(int a, int b) { int ret = 0; int zeroes = 0; for (int i = 1; i <= b; i <<= 1) { if (b & i) { b ^= i; if (!(a & b)) ret += 1 << zeroes; } if (!(a & i)) zeroes++; } return ret; } long long rec(int a, int b) { if (a == b) return 0; if (a == 0) return 2 * b - 1 + rec(1, b); long long ret = 0; if (a & 1) { ret += 2 * (f(a, b) - f(a, a)); a++; } if (b & 1) { ret += 2 * (f(b - 1, b) - f(b - 1, a)); b--; } return ret + 3 * rec(a / 2, b / 2); } int main() { int t; for (cin >> t; t--;) { int a, b; cin >> a >> b; cout << rec(a, b + 1) << '\n'; } return 0; }