A.膜法记录
二进制枚举行的状态,可以只枚举二进制1个数为a的状态。
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;cin>>t;
while(t--){
int n,m,a,b;
scanf("%d%d%d%d",&n,&m,&a,&b);
string s[n];
for(int i=0;i<n;i++)cin>>s[i];
vector<int>v;
for(int i=0;i<1<<n;i++){
int x=__builtin_popcount(i);
if(x==a)v.push_back(i);
}
function<bool(int x)>fun=[&](int x){
vector<string>p;
for(int i=0;i<n;i++){
if(!(x>>i&1))p.push_back(s[i]);
}
int sz=p.size();
int ans=0;
for(int j=0;j<m;j++){
bool l=0;
for(int i=0;i<sz&&!l;i++){
l|=p[i][j]=='*';
}
ans+=l;
}
return ans<=b;
};
bool f=0;
for(int &x:v){
if(fun(x)){
f=1;
puts("yes");break;
}
}
if(!f)puts("no");
}
}B.阶乘
二分判断。
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;cin>>t;
while(t--){
int p;scanf("%d",&p);
if(p==1)
{
puts("1");continue;
}
vector<pair<int,int> >v;
for(int i=2;i*i<=p;i++){
if(p%i==0){
int cnt=0;
while(p%i==0)p/=i,cnt++;
v.push_back({i,cnt});
}
}
if(p>1)v.push_back({p,1});
if(v.size()==1&&v[0].second==1){
printf("%d\n",p);continue;
}
int sz=v.size();
function<bool(int mid)>ck=[&](int mid){
for(int i=0;i<sz;i++){
int ans=mid,cnt=0;
int x=v[i].first;
while(ans)cnt+=ans/=x;
if(cnt>=v[i].second)continue;
return 0;
}
return 1;
};
int l=v[sz-1].first,r=1e9+7;
int ans=l;
while(l<=r){
int mid=l+r>>1;
if(ck(mid))ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
}
}C.完全图
二分长度即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int t;cin>>t;
while(t--){
ll x,y;scanf("%lld%lld",&x,&y);
__int128 n=x,m=y;
if((m>=n*(n-1)/2)){
printf("%lld\n",x);
continue;
}
__int128 l=1,k=1,r=n;
while(r>=l){
__int128 mid=l+r>>1;
__int128 x=mid*(mid+1)/2;
if(n*mid-x<=m)k=mid,l=mid+1;
else r=mid-1;
}
while(n*k-k*(k+1)/2<=m)k++;
if(n*k-k*(k+1)/2>m)k--;
printf("%lld\n",(ll)k+1);
}
}E.A+B问题
puts("4294967296");G.树上求和
一棵树上经过一条边的路径数等于两端点节点数之积。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n;
vector<int>g[N];
vector<long long >v;
int dp[N];
void dfs(int u,int fa){
dp[u]=1;
for(int v:g[u]){
if(v==fa)continue;
dfs(v,u);
dp[u]+=dp[v];
}
}
void Dfs(int u,int fa){
if(fa){
v.push_back(1LL*dp[u]*(dp[fa]-dp[u]));
dp[u]=dp[fa];
}
for(int v:g[u]){
if(v==fa)continue;
Dfs(v,u);
}
}
int main(){
cin>>n;
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);Dfs(1,0);
sort(v.begin(),v.end());
long long ans=0;
for(int i=0,k=n-1;i<n-1;i++,k--){
ans+=v[i]*k;
}
printf("%lld\n",ans);
}H.奇怪的背包问题增加了
从大到小合并,可以利用栈来实现。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n;
int k[N],a[N],s[N],tp=0;
int f[32];
int main(){
int t;cin>>t;
while(t--){
scanf("%d",&n);
memset(f,0,sizeof f);tp=0;
for(int i=0;i++<n;scanf("%d",&k[i]),a[i]=k[i]);
sort(a+1,a+1+n,greater<int>());
for(int i=1;i<=n;i++){
int v=a[i];
while(tp&&s[tp]==v)v++,tp--;
s[++tp]=v;f[a[i]]++;
if(s[1]==30)break;
}
if(s[1]!=30)printf("impossible\n");
else{
for(int i=1;i<=n;i++){
if(f[k[i]])f[k[i]]--,putchar('1');
else putchar('0');
}
putchar(10);
}
}
}I.寻找子串
尺取。
#include<bits/stdc++.h>
using namespace std;
string KP(string s) {
int st = 0;
int len = s.size();
for(int i = 1; i < len; i++) {
int sz = 0;
while(i+sz < len && s[st + sz] == s[i + sz]) {
sz++;
}
if(s[i + sz] > s[st + sz]) st = i;
if(i+sz == len) break;
}
return s.substr(st);
}
int main(){
string a;
cin>>a;
cout<<KP(a)<<endl;
}J.最大的差
MAX-MIN

京公网安备 11010502036488号