题意:懂得都懂
思路:由于n的范围很小,直接爆搜枚举一下a放到第几行,然后当枚举到a次的时候,判断一下需要几次b操作
代码:
#include<bits/stdc++.h>
using namespace std;
int const N=1e4+5;
#define int long long
void solve(){
int n,m,a,b;
cin>>n>>m>>a>>b;
vector<vector<char>>mp(n+1,vector<char>(m+1));
vector<bool>vis(n+1,false);
bool st=0;
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
cin>>mp[i][j];
}
}
function<void (int)>dfs=[&](int cnt){
if(st)return ;
if(cnt==a){
int ct=0;
for (int i = 1; i <=m ; ++i) {
for (int j = 1; j <=n ; ++j) {
if(!vis[j]&&mp[j][i]=='*'){
ct++;
break;
}
}
}
if(ct<=b){
st=1;
return ;
}
}
else{
for (int i = 1; i <=n ; ++i) {
if(!vis[i]){
vis[i]=1;
dfs(cnt+1);
vis[i]=0;
}
}
}
};
dfs(0);
if(st){
cout<<"yes\n";
}
else{
cout<<"no\n";
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int t;
cin>>t;
while(t--){
solve();
}
}
题意:懂得都懂
思路:我们找出p的质因子和个数,然后我们知道n越大就越可能是p的倍数,二分答案,我们可以求出当前的mid的阶乘mid!能够分成几个p的第i个质因子,然后我们判断是否≥我们所需要的i.second,由于质因子之间相互独立,因此我们检验质因子a的时候,对b无影响,因此检验完之后恢复mid值检验下一个即可
代码:
#include<bits/stdc++.h>
using namespace std;
int const N=1e4+5;
#define int long long
void solve(){
int n;
unordered_map<int,int>has;
int x;
cin>>x;
int p=x;
for (int i = 2; i <=x/i ; ++i) {
while (x%i==0){
has[i]++;
x/=i;
}
}
if(x>1)
has[x]++;
auto check=[&](int mid){
for (auto i:has) {
int y=mid;
int cnt=0;
while(y){
cnt+=y/i.first;
y/=i.first;
}
if(cnt<i.second)return false;
}
return true;
};
int l=1,r=p;
int ans=-1;
while(l<=r){
int mid=l+r>>1;
if(check(mid)){
r=mid-1;
ans=mid;
}
else{
l=mid+1;
}
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int t;
cin>>t;
while(t--){
solve();
}
}
题意:给一个n个点的图,每个点都与其他任何点相连,即每个点n-1条边,问如果可以删除m条边,这个图最多分成几个连通块
思路:我们新增加一个连通块需要删除n-1条边,第二个需要n-2,因此我们可以推出新增加最多的n-1个连通块,需要删1+2+3+4+n-1条边,因此我们可以二分答案,问新增加mid个连通块需要删除几条边,即可,要开__int128
代码:
#include<bits/stdc++.h>
using namespace std;
#define int __int128
int read()
{
int res=0;
char scan[1005];
scanf("%s",scan);
for(int i=0;i<strlen(scan);i++)
res*=10,res+=scan[i]-'0';
return res;
}
signed main(){
int t;
t=read();
while(t--){
int a,b;
a=read(),b=read();
__int128 n,m;
n=a,m=b;
__int128 l=0,r=n-1;
if(m>=(n-1)*n/2){
cout<<(long long)a<<"\n";
}
else{
__int128 x=n-1;
auto check=[&](__int128 mid){
__int128 res=(n-mid)-1;
res=x*(x+1)/2-res*(res+1)/2;
return res<=m;
};
int ans=0;
while(l<=r){
int mid=l+r>>1;
if(check(mid)){
ans=mid;
l=mid+1;
}
else{
r=mid-1;
}
}
ans+=1;
cout<<(long long)ans<<endl;
}
}
}
题意:给一个n个点,n-1条边的树,我们为每一条边赋值(1到n-1),每一条边只能赋值一种,问到任意点到任意点的权值之和最小是多少,比如样例之中,到4的点有3个,因此w4的权值是3 1 2,3-1这条边,2的左边有两个点,右子树有2个点(包括自己),因此这条边的w就是1 2 2=4
思路:我们可以知道一个边的贡献是左边的点的个数 右边点的个数再乘权值,因此我们根据点的乘积来排序,然后最大的乘最小边权,即可,我们处理点的乘积时,可以通过dfs寻早点,比如从3开始搜,到右边最底部为3个点,那么左边就是4-3,一个点。然后就是3 1;
代码:
#include<bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
void solve(){
int n;
cin>>n;
vector<int>q[n+1];
for (int i = 1; i <n ; ++i) {
int a,b;
cin>>a>>b;
q[a].push_back(b);
q[b].push_back(a);
}
vector<int>ans;
function <int (int,int)>dfs=[&](int u,int v){
int sum=1;
for (int i = 0; i <q[u].size() ; ++i) {
if(q[u][i]!=v){
sum+=dfs(q[u][i],u);
}
}
ans.push_back(sum*(n-sum));
return sum;
};
dfs(1,-1);
int res=0;
int l=n-1;
sort(ans.begin(),ans.end());
for (int i = 1; i <ans.size() ; ++i) {
res+=(ans[i]*l);
l--;
}
cout<<res<<endl;
return;
}
signed main(){
int t=1;
while (t--){
solve();
}
}