T1 Algor
直接DFS
都不用状压DP
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e5+5,INF=1e9;
int n,m,x;
int a[100][100],f[100],ans=INF;
bool check(){
for(int i=1;i<=m;++i)
if(f[i]<x) return false;
return true;
}
void DFS(int pos,int wei){
if(pos>n+1) return;
if(wei<ans&&check()) ans=wei;
for(int i=1;i<=m;++i) f[i]+=a[pos][i];
DFS(pos+1,wei+a[pos][0]);
for(int i=1;i<=m;++i) f[i]-=a[pos][i];
DFS(pos+1,wei);
return;
}
int main(){
n=in,m=in,x=in;
for(int i=1;i<=n;++i)
for(int j=0;j<=m;++j)
a[i][j]=in;
DFS(1,0);
if(ans!=INF) printf("%d\n",ans);
else puts("-1");
return 0;
}
注意边界
top
T2 Sumd
终于有质数筛经验啦!!!
筛一遍质数
然后分解正因子就完事
个鬼
O ( n 3 2 ) O(n^{\frac{3}{2}}) O(n23)T飞
考虑换一个方向
累加倍数
每一个数都要统计
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
signed main(){
int n=in,ans=0;
for(int i=1;i<=n;++i){
int cnt=n/i;
ans+=i*cnt*(cnt+1)/2;
}
cout<<ans<<endl;
return 0;
}
T3 Mouse
贪心
小根堆优化
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e5+5;
int n,tim,ans;
struct node{
int t,v;
}p[N];
priority_queue<pair<int,int> >q;
bool cmp(const node &a,const node &b){
return a.t<b.t;
}
int main(){
n=in;
for(int i=1;i<=n;++i) p[i].t=in;
for(int i=1;i<=n;++i) p[i].v=in;
sort(p+1,p+n+1,cmp);
for(int i=1;i<=n;++i){
if(tim<p[i].t) tim=p[i].t;
q.push(make_pair(-p[i].v,p[i].t));
while(q.size()>tim) q.pop();
}
while(q.size()){
ans-=q.top().first;
q.pop();
}
printf("%d\n",ans);
return 0;
}
T4 Treelis
不难
树上DP
树形DP都算不上
先来一波T飞的 O ( n 2 ) O(n^2) O(n2)
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=2e5+5;
int n,wei[N],f[N],faz[N];
vector<int>G[N];
void DFS(int u,int fa){
faz[u]=fa;
f[u]=f[fa];
int x=u;
while(x){
x=faz[x];
if(wei[x]<wei[u]) f[u]=max(f[u],f[x]+1);
}
for(int e=0;e<G[u].size();++e){
int v=G[u][e];
if(v==fa) continue;
DFS(v,u);
}
return;
}
int main(){
n=in;
for(int i=1;i<=n;++i) wei[i]=in;
for(int i=1;i<n;++i){
int u=in,v=in;
G[u].push_back(v);
G[v].push_back(u);
}
f[1]=1;
DFS(1,0);
for(int i=1;i<=n;++i)
printf("%d\n",f[i]);
return 0;
}
优化:
回溯的思想:
先记录一波改变的值,回溯回来之后还原回去
这道题中要改变单调递增子序列的内容和长度
写的时候中间二分写丑了
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=2e5+5;
int n,wei[N],f[N],a[N],ans;
vector<int>G[N];
void DFS(int u,int fa){
int rec_ans,rec_change,l,r;
for(int e=0;e<G[u].size();++e){
int v=G[u][e];
if(v==fa) continue;
rec_ans=ans,rec_change=0;
if(a[ans]<wei[v]) a[++ans]=wei[v];
else{
l=0,r=ans;
while(l+1<r){
int mid=l+r>>1;
if(a[mid]<wei[v]) l=mid;
else r=mid;
}rec_change=a[r],a[r]=wei[v];
}
f[v]=ans;
DFS(v,u);
ans=rec_ans;
if(rec_change) a[r]=rec_change;
}
return;
}
int main(){
n=in;
for(int i=1;i<=n;++i) wei[i]=in;
for(int i=1;i<n;++i){
int u=in,v=in;
G[u].push_back(v);
G[v].push_back(u);
}
ans=1;
f[1]=1;
a[1]=wei[1];
DFS(1,0);
for(int i=1;i<=n;++i)
printf("%d\n",f[i]);
return 0;
}
T5 Set
终于!!
质数经验!!!
转图
DFS直接连通块(我好像又把Tarjan忘了)
好像用并查集要优一些
而且这次可以大胆地路径压缩了
注意边界
那样舒服那样写
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e5+5;
int l,r,P,p[N],tot;
bool is[N],vis[N];
int father[N];
int getfather(int x){
return x==father[x]?x:getfather(father[x]);
}
void init(){
is[1]=is[0]=true;
for(int i=2;i<=N;++i){
if(!is[i]) p[++tot]=i;
for(int j=1;j<=tot&&i*p[j]<=r;++j){
is[i*p[j]]=true;
if(i%p[j]==0) break;
}
}
return;
}
int main(){
l=in,r=in,P=in;
init();
for(int i=l;i<=r;++i) father[i]=i;
for(int i=1;i<=tot;++i){
if(p[i]<P) continue;
int tmp=l/p[i]*p[i];
while(tmp<l) tmp+=p[i];
int f=tmp;
while(tmp<=r)
father[getfather(tmp)]=getfather(f),
tmp+=p[i];
}
int ans=0;
for(int i=l;i<=r;++i){
int fa=getfather(i);
if(!vis[fa]){
vis[fa]=true;
++ans;
}
}
printf("%d\n",ans);
return 0;
}