題意:給定n,p,k n個數,然後取連續的一段,讓著一段的sum%p<=k,然後求滿足條件的最大sum/p
思路:見注釋
/*view code取一段[l,r]讓這個區間和取模後小於等於k
切記,取模操作符合減法的分配定律
條件可以轉化為(sum-pre[l]-suf[r])%p<=k ===>(sum%p-pre[l]%p-suf[r]%p<=k
方法就是列舉這個pre[l]%p,然後可以藉此確定suf[r]%mod的最右邊的位置,更新最大值即可 */
#include
using
namespace
std;
typedef
long
long
ll;#define pb push_back
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
const
int m=1e6+6
;ll tree[m
<<2
],w[m],suf[m],pre[m],prel[m],sufr[m];
void up(int
root)
void build(int root,int l,int
r)
int midd=(l+r)>>1
; build(lson);
build(rson);
up(root);
}ll query(
int l,int r,int root,int l,int
r)
int midd=(l+r)>>1
; ll res=-2
;
if(l<=midd)
res=max(res,query(l,r,lson));
if(r>midd)
res=max(res,query(l,r,rson));
return
res;
}ll p;
ll mm(ll x)
intmain()
printf(
"case %d:
",sign);
ll summod=pre[n]%p;///
總的字首和取模
if(summod<=k)
suf[n+1]=0
;
for(int i=n;i>=1;i--)
build(
1,1,p);///
依照sufr來做線段樹,下標是字尾和取模,tree存的是位置
for(int i=1;i///
列舉從左開始的模p意義下的字首和
if(prel[i]==-1
)
continue
;
int temp=summod-i;///
總的減去左邊
int r=mm(temp);
int l=mm(temp-k);
if(l==0||l>r)///
查詢區間不合法
continue
;
int pos=query(l,r,1,1,p);//
返回滿足條件的最大值,即最後的座標
if(pos<=prel[i]+1)///
因為至少要取乙個袋子,所以如果pos==prel[i]+1,那麼利用下面步驟的處理就會選到0個袋子,所以不可取
continue
; ll x=pre[n]-pre[prel[i]]-suf[pos];
ans=max(ans,x/p);
}printf(
"%lld\n
",ans);
}return0;
}
E Magic Stones (思維好題)
題意 給出a陣列,b陣列,下標為2 n 1 可以進行操作,a i a i 1 a i 1 a i 問進行若干次操作,能否將a陣列變成b陣列 思路 真是一道很巧妙的題目。對三個數字a i 1 a i a i 1,d1 a i a i 1 d2 a i 1 a i a i 可以這樣看,a i a i 1...
D Perfect Groups 思維好題
一道挺不錯的題目。定義乙個陣列的答案 將這個陣列分成k組,每組裡面任意一對數字乘積都是平方數,k要最小。題目給出乙個n個長度的大小,要你求每個子陣列的答案,最後輸出答案為1.2,3 n的子陣列各有多少個。n最大是5000,子陣列個數是n n 1 2,n平方也是沒問題的,因此我們只要考慮,如果o 1 ...
D Cleaning 思維好題 字首)
題意 n個數,現在你可以取出相鄰的都不為0的數,使得他們同時減1,如果乙個堆為0了,它並不會消失掉,此時我們有至多一次機會操作,交換相鄰兩個數的位置,問能不能使得全部的數都變為0.思路 首先發現,端點一定要 後面的值,不然肯定不成立。於是a2 a1,減了之後a2 a2 a1 此時a2變成端點,同理可...