【CodeForces - 1066A~E】水题,模拟(有技巧),思维,题意难懂的模拟,二进制问题(有技巧)
A.
題目大意:
? ?x坐標上1~L有L個點都是整數,每v個長度就有一個燈亮著,但是有 [ l , r ] 這段區間上有列火車擋住了,問你能看到多少亮燈。
解題報告:
? ?大水題啊,找幾個樣例就會發現需要特殊處理一下左邊界恰好有燈的情況。
AC代碼:
#include<bits/stdc++.h>using namespace std; int L,v,l,r,ans; int main() {int t;cin>>t;while(t--) {scanf("%d%d%d%d",&L,&v,&l,&r);ans = (L/v) - (r/v - l/v);if(l%v==0) ans--;printf("%d\n",ans);}return 0 ; }?
B.
題目大意:
? ? 一個大小為n的數組代表n個房間,數組第i個元素為1代表在第i個房間有一個熱水器,可以熱給范圍為[i-r+1,i+r-1]范圍的房間熱水,問最少需要多少熱水器,可以供給所有房間。
解題報告:
? ?模擬一下過程就好了,記得終點不是在n,而是要加一個常數。因為有那一步i=cur,所以時間不是線性的,而是近似o(n^2)了。
AC代碼:
#include<bits/stdc++.h>using namespace std; int a[100005]; int main() {int n,r,flag=1;cin>>n>>r;r--;for(int i = 1; i<=n; i++) scanf("%d",a+i);int cur = 0,now = 0,cnt = 0;int pos = 1;for(int i = 1; i<=n+2000; i++) {if(pos > n) break;if(a[i] == 1) {if(i-pos <= r) {now = i;}}if(i-pos > r) {if(now == cur) {flag=0;break;}cnt++;cur=now;pos = cur + r + 1;i=cur;}}if(flag == 0) puts("-1");else printf("%d\n",cnt);return 0 ; }另附一種模擬思路:(就是徹徹底底的o(n^2)了,每次都從末尾開始找,找到的第一個滿足條件的一定是我們喜歡的,不過反正n很小,n^2也不慫,主要是這種思路不容易寫萎了啊)
#include<bits/stdc++.h> #define ll long long using namespace std; const int MAX = 1e3+5; int n,r; int a[MAX]; int main() {scanf("%d%d",&n,&r);for(int i=1; i<=n; i++)scanf("%d",&a[i]);int last = 0,num = 0;bool flag;int pos;while(1) {if(last>=n) break; flag = false;int pp = max(last-r+1,0);for(int i=n; i>pp; i--) {if(a[i]) {if(i-r<=last) {pos = i;flag = true;break;}}}if(!flag) {printf("-1\n");return 0;}last = pos+r-1;num++;}printf("%d\n",num);return 0; }wjh的代碼:
#include<bits/stdc++.h> #include<queue> using namespace std; int a[2000]; int main() {int n,r;scanf("%d%d",&n,&r);for(int i=1; i<=n; i++) {scanf("%d",&a[i]);}int d=r;int flag=0;for(int i=r; i>=1; i--) {if(a[i]==1) {flag=i;break;}}int ans=1;if(flag==0) {printf("-1\n");} else {int wi=flag;int ff=0;while(wi+r-1<n) {d=wi+r+r-1;ff=0;for(int i=d; i>wi; i--) {if(a[i]==1) {ff=1;wi=i;ans++;break;}}if(ff==0)break;}if(wi+r-1>=n)printf("%d\n",ans);else {printf("-1\n");}}return 0; }?剛開始? ?在最后判斷的時候寫成了if(ff=0),就錯了,因為滿足不了第一次就完成的 ?就進不去while了?
C.
題目大意:
開始空隊列,三種操作,可以進行前插和后插,查詢使某個數的為最左或最右需要去掉的最少數字(其實也就是距離隊列最左端或者最右端哪個更近)。
解題報告:
? ?這題如果想著,每次加入一個答案都去維護之前的所有的值,那就走遠了。這題完全可以記錄一下位置然后中間完全不用維護,最后直接輸出結果就可以了。
#include<bits/stdc++.h>using namespace std; int q,l,r,tmp; char op[5]; int a[500005]; int main() {cin>>q;l = 0,r = 0;for(int i = 1; i<=q; i++) {scanf("%s",op);if(op[0] == 'L') {scanf("%d",&tmp);a[tmp] = --l;if(i == 1) r--;}else if(op[0] == 'R') {scanf("%d",&tmp);a[tmp] = ++r;if(i == 1) l++;}else {scanf("%d",&tmp);printf("%d\n",min(r-a[tmp],a[tmp]-l));}}return 0 ; }?
D.
題目大意:
有n個物品,、第一給物品開始往右邊挑選,對于每一個物品,如果可以放得下的就直接放進盒子,若目前的盒子放不下,那就要另外開一個盒子來放物品了,若目前還有可用的盒子,那就繼續選取下去,若目前已經沒有可用的盒子了,說明這次選取是不對的,那么選取的第一個物品退回去,看是否有剩余的空間放下該物品,如果還是放不下的話,繼續把第二個拿的物品退回去,直至可以放下該物品為止,然后繼續選取下去。
解題報告:
? 讀懂題了就很簡單,就是往盒子里按照給定的順序放東西,如果放滿了就新開一個盒子放東西,如果都滿了,那就把最早放入的物品拿出來,然后繼續放后面的物品,直到放到最后一個物品。問你盒子中最多有多少物品?。。。就是這一句話,好有迷惑性,一般都會感覺是中間過程也會算上,而且不能打亂順序放,所以不能排序,就是必須按照他的algorithm放東西,所以就不好模擬了啊!但是其實題意是就問你最后盒子中物品的數量,而不是中間某個過程就算物品很多,也被拿出來了,那也 白搭,所以只和最終狀態有關,,這樣正著還是不好模擬,所以采用時光倒流法,,,倒著模擬,就簡單多了,或者先二分從第幾個盒子開始裝,然后再驗證是否可行即可(也可以二分最終裝了多少個物品,不過其實一樣的因為反正都是倒著裝)。不過這個題的二分沒啥亂用,,因為直接模擬就出結果了。
#include <bits/stdc++.h> #define ll long longusing namespace std; int n,box,siz; int a[200005];bool ok(int mid){int k=1,rem=siz;for(int i = mid; i<=n; i++){if(rem<a[i]){rem=siz;k++;}if(k>box) return 0;rem-=a[i];}return 1; } int main() {cin>>n>>box>>siz;for(int i = 1; i<=n; i++) cin>>a[i];int mid,l=1,r=n,ans;while(l<=r){mid=(l+r)/2;if(ok(mid))ans=mid,r=mid-1;else l=mid+1;}cout << n + 1 -ans << endl;return 0; }?
E.
題目大意:
? ?給你長度分別為n,m的二進制串,當b>0時,對a,b,&運算結果為tmp,然后b右移一位,把每次a&b的10進制結果(tmp)累加得到sum,結果輸出sum對998244353取余的值。
解題報告:
? 模擬過程不難發現,a的每一個位置做出的貢獻次數,就是b對應位置前綴1的個數,于是維護一下就好了。(因為b字符串一直在變,但是a是固定不變的啊!所以我們預處理一下a字符串)
#include<bits/stdc++.h> #define ll long long using namespace std; int n,m; const ll mod = 998244353; char op[5]; char a[500005],b[500005]; ll ans[500005]; ll qpow(ll a,ll k) {ll res = 1;while(k) {if(k&1) {res *= a;res %= mod;}k>>=1;a=(a*a)%mod;}return res; } int main() {ll cha = 0;cin>>n>>m;cin>>(a+1);cin>>(b+1);ll lena = strlen(a+1);ll lenb = strlen(b+1);ll cur = 0;if(strlen(a+1) < strlen(b+1)) {cha = strlen(b+1) - strlen(a+1);for(ll i = 1; i<=cha; i++) {if(b[i] == '1') cur++;}for(ll i = 1; i<=strlen(a+1); i++) {if(b[i+cha]=='1') ans[i] = ++cur;else ans[i]=cur;}}else {cha = strlen(a+1) - strlen(b+1);for(ll i = 1; i<=strlen(b+1); i++) {if(b[i] == '1') ans[i+cha] = ++cur;else ans[i+cha] = cur;}}ll out = 0;for(ll i = 1; i<=strlen(a+1); i++) {if(a[i] == '1') {out += (ll)ans[i] * qpow(2,lena-i);out %= mod;}}printf("%lld\n",out%mod);return 0 ; }比賽的時候忘記考慮a比b長的情況了、、不然這場比賽完美了啊。?最后壓哨失敗很難受。。
這道題還有更精彩更簡潔的解法,把兩個字符串處理成相同長度的,再去維護,豈不是美滋滋?正好用到了string類,重載 ' + ' 焦作人啊!另外,這個代碼中預處理了2^n,做到了o(1)出結果,比快速冪的log要好一些。
AC代碼2:
#include<bits/stdc++.h> using namespace std; #define ll long long const ll mod=998244353; const ll N=2e5+10; ll one[N],pw[N]; int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); ll i,j,k,n,m;string a,b;cin>>n>>m;cin>>a>>b;//使位數一致在位數少的前面加0 if(n<m){a=string(m-n,'0')+a;}else if(m<n){b=string(n-m,'0')+b;}n=max(n,m);one[0]=(b[0]=='1');for(i=1;i<n;i++) one[i]=one[i-1]+(b[i]=='1');//b高位開始的前綴和 pw[0]=1;for(i=1;i<N;i++) pw[i]=pw[i-1]*2ll%mod;//計算2的冪次預處理 ll ans=0;for(i=0;i<n;i++){ll res=(a[i]=='1');res=res*pw[n-i-1]%mod;//計算a這個位置的10進制值 ans=(ans+res*one[i]%mod)%mod;//之所以*one[i],是因為b右移的過程,a[i]對應的次數就是b高位開始的前綴和,注意取余mod }cout<<ans<<endl;return 0; }?
總結
以上是生活随笔為你收集整理的【CodeForces - 1066A~E】水题,模拟(有技巧),思维,题意难懂的模拟,二进制问题(有技巧)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 宣称可抗幽门螺旋杆菌 薇娅丈夫公司违反广
- 下一篇: 不怕删错了!微信iOS版8.0.24更新