CF507
CF507A
真就可以贪心解决的背包问题了
价值为1 贪心选取重量最小的即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define inl inline
#define ll long long
const int N=1e5+5;
const int M=1e6+5;
const int inf=0x7fffffff;
inl int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
inl void write(int x){
if(x<0){putchar('-');x=-x;}
if(x>9)write(x/10);
putchar(x%10+'0');
}
inl void writel(int x){write(x);putchar('\n');}
inl void writei(int x){write(x);putchar(' ');}
int n,k,ans;
struct node{
int v,id;
friend bool operator<(node a,node b){return a.v<b.v;}
}a[N];
vector<int>v;
signed main(){
n=read();k=read();
for(int i=1;i<=n;i++)a[i]={read(),i};
sort(a+1,a+n+1);
for(int i=1;i<=n&&a[i].v<=k;i++)k-=a[i].v,ans++,v.push_back(a[i].id);
writel(ans);
for(auto i:v)writei(i);
return 0;
}
CF507B
容易发现一个性质:在圆心 \(2r\) 范围内的所任意一点都可以一次旋转到达
证明:对于距离小于 \(2r\) 的两点 一定可以从到垂直平分线距离为 \(r\) 的点旋转得到
那么每次尽量走 \(2r\) 剩下的距离一次微调即可 那么答案 \(\lceil \dfrac{d}{2r}\rceil\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define int ll
#define gc getchar
#define pc putchar
const int N=1.6e3+5;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
const int mod=1e6+3;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int n,m,r,x,y,xx,yy;
signed main(){
r=read();x=read();y=read();xx=read();yy=read();
double dis=sqrt((xx-x)*(xx-x)+(yy-y)*(yy-y));
writel(ceil(dis/(r<<1)));
return 0;
}
CF507C
题意相当于:
按照左右左右顺序向儿子遍历 如果没找到向上找第一个有没走过的儿子的节点 然后遍历
且如果当前是父亲的左儿子 下次一定遍历右儿子 反过来同理
会发现如下性质:如果一个节点子树内没有要找的叶子子 那么也一定会找遍这个子树才返回
那么我们dfs 如果子树内不含要找的叶子累加子树贡献然后返回 有的话就累加自己贡献然后递归
叶子个数、子树大小都是2的几次方 这个可以预处理 但我偷懒用pow了
最优复杂度 \(O(h)\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define endl '\n'
#define int ll
#define gc getchar
#define pc putchar
const int N=1.6e3+5;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
const int mod=1e6+3;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int n,m,h,ans;
inl bool dfs(int dep,int pos,int op){
if(dep>h||dep==h&&pos==n)return 1;
if(n<pos||n>pos+pow(2,h-dep)-1)return ans+=pow(2,h+1-dep)-1,0;
ans++;
if(!dfs(dep+1,pos+(op^1)*pow(2,h-dep-1),op^1))
return dfs(dep+1,pos+op*pow(2,h-dep-1),op);
else return 1;
}
signed main(){
h=read();n=read();
dfs(0,1,1);
writel(ans);
return 0;
}
CF507D
比较板的数位dp。
要求后缀为 \(k\) 倍数 所以需要从低位到高位枚举
注意要求后缀不为0 被这个坑完了 翻译能不能有点树脂()
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define endl '\n'
#define int ll
#define gc getchar
#define pc putchar
const int N=1.6e3+5;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
const int mod=1e6+3;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int n,m,k,f[1005][105][2],ans,poww[N];
inl int dfs(int pos,int x,int opt,int zero){
if(!pos)return opt&&zero;
if(~f[pos][x][opt])return f[pos][x][opt];
int ret=0;
for(int i=pos==1;i<=9;i++)
ret=(ret+dfs(pos-1,(i*poww[n-pos]%k+x)%k,opt|(!((i*poww[n-pos]%k+x)%k)&&(zero|(bool)i)),zero|(bool)i))%m;
return f[pos][x][opt]=ret;
}
signed main(){
n=read();k=read();m=read();
poww[0]=1;
for(int i=1;i<=n;i++)poww[i]=poww[i-1]*10%k;
memset(f,-1,sizeof f);
writel(dfs(n,0,0,0));
return 0;
}
CF507E
可以发现 要找的最短路满足要修的路最少 情况一定更优 里面修的路少 外面砸的路也少
那么跑dij 让满足dis最小前提下 修的路最少即可
dij最短路模型保证当前点松弛前所有可能的最小dis值都被更新 所以答案是对的
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define endl '\n'
#define int ll
#define gc getchar
#define pc putchar
const int N=2e5+5;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
const int mod=1e6+3;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int n,m,k,dis[N],num[N],vis[N],pst[N],flag[N];
int head[N],frm[N],nxt[N],to[N],w[N],cnt=1;
inl void add(int u,int v,int c){
nxt[++cnt]=head[u];
frm[cnt]=u;
to[cnt]=v;
w[cnt]=c;
head[u]=cnt;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
inl void dij(){
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
dis[1]=0;q.push({0,1});
while(!q.empty()){
int x=q.top().second;q.pop();
if(vis[x])continue;vis[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=to[i],c=!w[i];
if(dis[y]>dis[x]+1){
dis[y]=dis[x]+1;
num[y]=num[x]+c;
pst[y]=i;
q.push({dis[y],y});
}else if(dis[y]==dis[x]+1&&num[y]>num[x]+c){
num[y]=num[x]+c;
pst[y]=i;
}
}
}
}
vector<tuple<int,int,int>>v;
signed main(){
n=read();m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read(),c=read();
add(u,v,c);add(v,u,c);
}
dij();
int x=n;
while(x^1){
flag[pst[x]]=flag[pst[x]^1]=1;
x=frm[pst[x]];
}
for(int i=2;i<=cnt;i+=2){
if(flag[i]==w[i])continue;
v.push_back(make_tuple(frm[i],to[i],flag[i]));
}
writel(v.size());
for(auto i:v)
writei(get<0>(i)),writei(get<1>(i)),writel(get<2>(i));
return 0;
}

浙公网安备 33010602011771号