反思:强调,一定要把题看清楚了再写,真的会浪费很多时间,比如B,看到的第一眼还以为是前几天补过的题目,其实不是(可能会有很多环);一定要把所有题都尽量过一遍,就比如说c,就前几天才补过的题,不写好可惜;敢于暴力,勇于暴力,请多尝试(无语,该思考的时候不思考,不该想的时候想多了)
阶段一
思路:暴力,不太会算时间复杂度
代码:
int main() {
int n;
cin >> n;
long long sum = 0;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
sum ^= a[i]; }
long long ans = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n / i; j++)
{
ans = max(ans, sum ^ a[i] ^ (a[i] + j));
ans = max(ans, sum ^ a[i] ^ (1ll * a[i] * j));
}
}
cout << ans << '\n';
return 0;
}
阶段二
思路:板子题,前几天补过,但是因为看这个题看的有点晚,所以没写,再写了一遍匈牙利算法求二分图的最大匹配
再强调一遍,这里没有我喜欢的零食
正确代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=110,M=2e5+10;
int n;
int connect[510][510];
int p[510];
int cp[510];
bool check(int x){
for (int j=1; j<=n; j++){
if (connect[x][j]==1 && p[j]==0){
p[j]=1;//记录搜索状态
if (cp[j]==0|| check(cp[j])){
cp[j]=x;
return true;
}
}
}
return false;
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
int k;
cin>>k;
int tt=0;
while(tt<k){
int x;
cin>>x;
connect[i][x]=1;
tt++;
}
}
int ans=0;
for(int i=1;i<=n;i++){
memset(p,0,sizeof p);
if(check(i)) ans++;
}
if(ans==n) cout<<"Yes"<<endl;
else {cout<<"No"<<endl;cout<<n-ans<<endl;}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
题解:
要求区间[l, r]的1的个数,显然我们可以用前缀和去计算,即区间[1, r]的个数减去区间[1, l − 1] 的个数作为答案。
下面考虑如何计算区间[1, r]的个数:
我们按位考虑,从最低位开始,显然最低位上是01 01 01循环,也就是两种情况,我们在此基础 上去考虑下一位,只看当前位的话仍然只有01两种情况,但是当我们结合上一位,一个0就是对 应上一位的所有情况,1同理,那么这一位就是0 0 1 1,以此类推,设当前位是第k位,那在当前 位上循环节就是2k+1 (2k个0和2k个1)每一位累加即可。
代码:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f3f
using namespace std;
using ll = long long;
const int N = 4e5 + 7;
const int mod = 998244353;
ll f(ll x, ll k)
{
ll y = 1ll << (k + 1);
ll ok = y / 2;
x++;
ll res=x/y*ok;// 循环节内部分 ll r = x % y;
ll r=x%y;
r -= ok;
if (r > 0)
res += r; // 计算循环节多余部分 return res;
return res;
}
void solve()
{
ll l, r;
cin >> l >> r;
ll ans = 0;
for (ll i = 61; i >= 0; i--)
{
ll p = (f(r, i) % mod - f(l - 1, i) % mod + mod) % mod;
ans = (ans + p) % mod;
}
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin>>t;
while (t--) {
solve();
}
return 0;
}
思路:1.将每一座城市的伤害以及他的序号放入vector中排序,以便找到在前i个中伤害最大的几个城市,从后往前遍历,用神力抵消他们的伤害,用前缀和记录前i个城市的伤害在前i个中伤害最大的几个城市,减去可以抵消的最大伤害,如果最后小于等于0,就往前一个城市推(但是最后案例过了85%,没改出来)
错误代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll __int128//ll的前缀和数据范围很大,所以用int128维护
#define PII pair<int,int>
int n,m,k;
bool cmp(PII x,PII y){
if(x.first==y.first) return x.second>=y.second;
return x.first>y.first;
}
void solve() {
cin>>n>>m>>k;
int a[n+10];
int b[n+10];//最好开成全局数组b[200010]
memset(b,0,sizeof b);
vector<PII>c;
for(int i=1;i<=n;i++) {
cin>>a[i];
b[i]=b[i-1]+a[i];
c.push_back({a[i],i});
}
sort(c.begin(),c.end(),cmp);
for(int i=n;i>=1;i--){
int tt=0;
int p=0;
int sum2=0;
while(c.size()-1>=p&&tt!=k){
if(c[p].second<=i){
sum2+=c[p].first;
tt++;
}
p++;
}
if(m>b[i]-sum2) {
cout<<i<<endl;
return ;
}
}
cout<<0<<endl;
return;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin>>t;
while (t--) {
solve();
}
return 0;
}
正解:
对于前 k 个国家,我们直接先选择消耗神力,从第 k + 1 个国家开始我们就从我们选择消耗神力 的 k 个国家中选择出一个在不消耗神力的前提下,需要消耗的生命力最小的国家,并假设该国家 为 i ,需要消耗的生命力为 ai 。同时我们设我们当前所在的国家为 j ,需要消耗的生命力为 aj 。 若 ai > aj ,则我们选择在第 j 个国家消耗生命力,仍在第 i 个国家消耗神力,这样可以保证我 们的生命力消耗的最小;反之,则我们选择在第 i 个国家消耗生命力,在第 j 个国家消耗神力, 以此来逐渐更新,保证答案最大。这个过程类似于一个反悔贪心的过程。最后当发现无法畅游某 一个国家或可以旅行完全部国家时就代表找到答案了。
注意:本题中 ∑n ai 的值会超出 long long 类型的数据范围,因为 m 的取值范围没有超出 i=1
long long 类型 故若找到答案之后立刻结束则可以保证不会超出 long long 的数据范围。当然, 若使用 __int128 类型,则不必担心这个问题。
因为本题只遍历一遍,时间复杂度为 O(n),而优先队列的每次pop和push的时间复杂度为 O(logn) ,所以本题的时间复杂度为O(nlogn)。