觀察樣例發現大概是 \(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; }