A
题意:
1,2,,,,n
对于第j次操作,每一个加j除了选中的一个不加之外
让他们变成相同的
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve()
{
int n;
cin>>n;
cout<<n<<endl;
for(int i=1;i<=n;i++)
cout<<i<<" ";
cout<<endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--)
solve();
}
B
题意:两两可以乘上-1,问和最大,无非偶数全消去,奇数剩下一个,给abs最小的
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int inf=1e9+5;
void solve()
{
int min_=inf;
int flag=0;
int sum=0;
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int xx;
cin>>xx;
if(xx<0)
flag++;
if(abs(xx)<min_)
min_=abs(xx);
sum+=abs(xx);
}
}
if(flag%2==0)
cout<<sum<<endl;
else
{
cout<<sum-2*min_<<endl;
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--)
solve();
}
C
题意:
给你一个包W装物品,你只能装到[W/2,W]
很显然啊,先把大于W的去掉,就是说如果有一个大于W/2的直接输出,不然直接加直到大于W/2
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+5;
int a[maxn];
vector<int>vv;
void solve()
{
vv.clear();
int f=1;
int flag=0;
int sum=0;
int n,w;
cin>>n>>w;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]>=(w+1)/2&&a[i]<=w)
{
flag=i;
}
if(a[i]<=w)
{
f=0;
sum+=a[i];
}
}
if(f==1)
{
cout<<-1<<endl;
return ;
}
if(flag!=0)
{
cout<<1<<endl;
cout<<flag<<endl;
return;
}
if(sum<(w+1ll)/2)
{
cout<<-1<<endl;
return ;
}
sum=0;
for(int i=1;i<=n;i++)
{
if(a[i]>w)
continue;
sum+=a[i];
vv.push_back(i);
if(sum>=(w+1ll)/2)
{
break;
}
}
cout<<vv.size()<<endl;
for(int i=0;i<vv.size();i++)
cout<<vv[i]<<" ";
cout<<endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--)
solve();
}
D
题意:
给你两个字符串求a,b 求4*LCS(c,d)-c.size()-d.size()的最大值;
很显然看到LCS dp
维护状态转换的关系
using namespace std;
#include <bits/stdc++.h>
//#pragma GCC optimize(2)
//#pragma comment(linker, "/STACK:102400000,102400000")
#define int long long
const int maxn=5e3+5;
int dp[maxn][maxn];
void solve()
{
int max_=0;
int n,m;
string a,b;
cin>>n>>m>>a>>b;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i-1]==b[j-1])
dp[i][j]=dp[i-1][j-1]+2;
else
dp[i][j]=max(0ll,max(dp[i-1][j],dp[i][j-1])-1);
max_=max(max_,dp[i][j]);
}
}
cout<<max_;
}
signed main() {
int _=1;
//cin>>_;
while(_--)
solve();
return 0;
}
E
题意:
对于每个点i,找到j≠i且aj xor ai最小,连边(i,j)。
如果连边之后形成一棵树,那么称{ai}为合法的。
给出{ai},求至少删掉多少个点才合法。
n≤2∗105
ai互不相同
题解:
很显然整体异或和最小的那个值被划了两遍,其他的都不能被划两遍,所以除了最小的之外,其他的都只能和有一条异或和比他小的点连接;
哈夫曼0 1
结点分开越早,异或和越大,所有的点都在最下面的叶子,所以分开的时候也就分开了两个不同连通集合,很显然两个连通集是不能相连的,因为你内部的一点肯定比外部的异或和小,除非集合内只有一点,其他点全部删去,遍历删去的每一种情况,取剩下值的最大值,也就是删去的最小值,最后到两个点的时候他们两个都能放进去可以连通主要是
using namespace std;
#include <bits/stdc++.h>
//#pragma GCC optimize(2)
//#pragma comment(linker, "/STACK:102400000,102400000")
#define int long long
const int maxn=2e5+5;
struct node
{
int size;
int lc,rc;
node()
{
size=0;
lc=0;
rc=0;
};
};
int cnt;
node no[maxn*30];
void insert(int xx)
{
int now=0;
no[now].size+=1;
for(int i=29;i>=0;i--)
{
if(xx>>i&1)
{
if(no[now].rc==0)
{
cnt++;
no[now].rc=cnt;
}
now=no[now].rc;
}
else
{
if(no[now].lc==0)
{
cnt++;
no[now].lc=cnt;
}
now=no[now].lc;
}
no[now].size+=1;
}
}
int ans;
void dfs(int u,int s)
{
if(no[u].lc>0&&no[u].rc>0&&no[no[u].lc].size==1&&no[no[u].rc].size==1)
{
ans=max(ans,s+2);
return;
}
if(no[u].lc>0)
dfs(no[u].lc,s+(no[u].rc>0?1:0));
if(no[u].rc>0)
dfs(no[u].rc,s+(no[u].lc>0?1:0));
}
void bfs(int u)
{
cout<<no[u].size<<endl;
if(no[u].lc>0)
bfs(no[u].lc);
if(no[u].rc>0)
bfs(no[u].rc);
}
void solve()
{
cnt=0;
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
int xx;
cin>>xx;
insert(xx);
}
//bfs(0);
ans=2;
dfs(0,0);
cout<<n-ans;
}
signed main() {
int _=1;
//cin>>_;
while(_--)
solve();
return 0;
}