小藍的二進位制詢問
找規律,可以發現 把從0開始的十進位制數字轉化為二進位制。每一個二進位制位有0或1兩種狀態。從低到高的第一位以2為週期,第二位以4為週期,第三位以8為週期……也就是說第n位以 2^{n} 為週期。每個週期都是前一半是0,後一半是1 。
舉例:
000 001 010 011 100 ……
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=100;
long long f[N][N];
int a[N];
int k;
int mod = 998244353;
int c;
int ans = 0;
int get(int x) //計算x的二進位制長度
{
int cnt = 0;
while(x)
{
x/=2;
cnt++;
}
return cnt;
}
int solve(long long x)
{
ans = 0 ;
int cnt = get(x);
x++; //因為週期是從0開始算的
for(int i=1;i<=cnt;i++)
{
int tt = pow(2,i); //第i位的週期
ans += (x/tt)*(tt/2); //0~x 第i位1的個數
ans %= mod;
ans += max(0ll,x%tt-tt/2); //週期內仔細判斷
ans %= mod;
}
return ans;
}
signed main()
{
int t, l, r;
cin >> t;
while(t--)
{
cin >> l >> r;
int ans = (solve(r) - solve(l-1)+mod) % mod; //差分求區間
cout << ans << endl;
}
return 0;
}
旅途的終點
注意!是按既定的路線旅遊的!所以不能簡單地透過排序找出k個最大的點。
正解:維護一個元素從小到大的大小為k的優先佇列,從1~n按順序放入數。當佇列滿時,從隊首彈出最小的元素,放入接下來的元素。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
typedef pair<int,int> PII;
typedef unsigned long long ull;
const int ddx[8]={-1, 0, 1, 0, 1, -1, 1, -1};
const int ddy[8]={0, 1, 0, -1, -1, 1, 1, -1};
const int INF=0x3f3f3f3f;
const int N=6e5+10;
int n,m,k;
int a[N];
int sum = 0;
void solve()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>a[i];
priority_queue<int,vector<int>,greater<int>>q;
for(int i=1;i<=n;i++)
{
q.push(a[i]);
if(q.size()>k)
{
sum+=q.top();
q.pop();
}
if(sum>=m)
{
cout<<i-1<<endl;
return;
}
}
cout<<n<<endl;
return;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
//cin >> t;
while(t--) {
solve();
}
return 0;
}