裸的完全揹包……被孫到
把當作物品,容量爲
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
using namespace std;
typedef long long ll;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
const int Size=1000005;
int n,dp[Size],LOG[Size];
int main() {
// freopen("T1.in","r",stdin);
n=read();
dp[0]=1;
for(re i=0; i<=20; i++) {
for(re j=0; j+(1<<i)<=n; j++) {
dp[j+(1<<i)]=(dp[j+(1<<i)]+dp[j])%mod;
}
}
printf("%d",dp[n]);
return 0;
}
T2 貧富差距
是朋友就建一條的邊。
如果所有的點都在同一個聯通塊中,那麼貧富差距的最大值就是最長鏈的長度乘以(易證無法構造出更大的貧富差距)。
判-1用並查集,判是否所有的點在同一個聯通塊中即珂,如果有兩個點不在同一個聯通塊中,則這兩個點的貧富差距珂以無限擴大。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
using namespace std;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
inline char GetChar() {
char ch=getchar();
while(ch!='Y' && ch!='N') ch=getchar();
return ch;
}
const int Size=105;
int n,d,father[Size];
int Find(int x) {
if(x==father[x]) return x;
return father[x]=Find(father[x]);
}
int cnt,head[Size];
struct node {
int v,next;
} w[Size*Size<<1];
inline void AddEdge(int u,int v) {
w[++cnt].v=v;
w[cnt].next=head[u];
head[u]=cnt;
}
int Queue[Size],dis[Size];
bool vis[Size];
int bfs(int s) {
memset(vis,0,sizeof(vis));
int hd=0,tl=0;
Queue[++tl]=s;
vis[s]=true;
dis[s]=0;
int ans=0;
while(hd<tl) {
int x=Queue[++hd];
for(re i=head[x]; i; i=w[i].next) {
int nxt=w[i].v;
if(!vis[nxt]) {
vis[nxt]=true;
Queue[++tl]=nxt;
dis[tl]=dis[hd]+1;
if(dis[tl]>ans) {
ans=dis[tl];
}
}
}
}
return ans;
}
inline void init() {
memset(head,0,sizeof(head));
cnt=0;
for(re i=1; i<=n; i++) {
father[i]=i;
}
}
int main() {
// freopen("T2.in","r",stdin);
int T=read();
while(T--) {
n=read();
d=read();
init();
for(re i=1; i<=n; i++) {
for(re j=1; j<=n; j++) {
char ch=GetChar();
if(ch=='Y') {
AddEdge(i,j);
int fx=Find(i);
int fy=Find(j);
if(fx!=fy) {
father[fx]=fy;
}
}
}
}
int fa=Find(1);
bool inf=false;
for(re i=2; i<=n; i++) {
if(Find(i)!=fa) {
inf=true;
break;
}
}
if(inf) {
puts("-1");
continue;
}
int ans=0;
for(re i=1; i<=n; i++) {
int now=bfs(i);
if(now>ans) {
ans=now;
}
}
printf("%d\n",ans*d);
}
return 0;
}
T3 特殊的排列
找出序列上相鄰兩項差爲1的最長子序列,則這個子序列長度是最長的不用移動的長度。
證明:
1.移動一個子序列之外的數,子序列的相對順序不變。
2.不在最長子序列中的數一定要移動到序列首或序列末(否則珂以形成更長的相鄰兩項差爲1的子序列)。
3.不存在另一個更長的子序列,相鄰兩項差不爲1,且這個子序列中的數不用移動。因爲若相鄰兩項差不爲1,那麼這兩項之間的數必須要通過移動子序列裏的數來得到。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
using namespace std;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
const int Size=50005;
int dp[Size];
int main() {
int n=read();
int ans=0;
for(re i=1; i<=n; i++) {
int x=read();
if((dp[x]=dp[x-1]+1)>ans) {
ans=dp[x];
}
}
printf("%d",n-ans);
return 0;
}
T4 極品飛車
一個特殊的隱含條件是速度必須要>0,否則時間會變成負數或正無窮(長者:只有我才能操控負數和的時間,你們還是太naive)
列出式子,
因爲對於任意,有,所以左邊是單調遞減的。
所以二分,暴力判即珂。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
#define eps 1e-10
using namespace std;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
inline char GetChar() {
char ch=getchar();
while(ch!='Y' && ch!='N') ch=getchar();
return ch;
}
const int Size=1005;
int n;
double t,s[Size],d[Size];
double check(double mid) {
double ans=0;
for(re i=1; i<=n; i++) {
if(fabs(s[i]+mid)<eps) {
ans+=1e15;
} else {
ans+=d[i]/(s[i]+mid);
}
}
return ans;
}
int main() {
// freopen("T4.in","r",stdin);
n=read();
scanf("%lf",&t);
double minn=1e10;
for(re i=1; i<=n; i++) {
scanf("%lf %lf",&d[i],&s[i]);
if(s[i]<minn) minn=s[i];
}
double l=-minn+eps,r=1e7,mid;
for(re i=1; i<=1000; i++) {
mid=(l+r)/2;
if(check(mid)>=t) {
l=mid;
} else {
r=mid;
}
}
printf("%.6lf",l);
return 0;
}
/*
3 9
3 2
6 3
9 4
*/
T5 修改數組
首先把所有都減去,然後題目變成修改一些數,要求改成非負整數,且滿足序列不減。
把所有的提取出來,跑最長不降子序列。因爲序列不減,所以剩下的的部分一定能改成一個非負整數,使序列不減。
最後只有這個LIS的所有元素不用修改。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
using namespace std;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
const int Size=100005;
int n,maxn,a[Size],b[Size],tree[Size];
inline int lowbit(int x) {
return x&(-x);
}
inline void update(int x,int v) {
for(re i=x; i<=maxn; i+=lowbit(i)) {
if(v>tree[i]) {
tree[i]=v;
}
}
}
inline int query(int x) {
int ans=0;
for(re i=x; i; i-=lowbit(i)) {
if(tree[i]>ans) {
ans=tree[i];
}
}
return ans;
}
int main() {
n=read();
int tot=0;
for(re i=1; i<=n; i++) {
a[i]=read()-i;
if(a[i]>=0) {
b[++tot]=a[i];
}
}
for(re i=1; i<=tot; i++) {
a[i]=b[i];
}
sort(a+1,a+1+tot);
maxn=unique(a+1,a+1+tot)-(a+1);
for(re i=1; i<=tot; i++) {
b[i]=lower_bound(a+1,a+1+maxn,b[i])-a;
}
int ans=0;
for(re i=1; i<=tot; i++) {
int x=query(b[i]);
update(b[i],x+1);
if(x+1>ans) {
ans=x+1;
}
}
printf("%d",n-ans);
return 0;
}
/*
12
3 3 6 6 1 2 6 1 1 3 6 4
*/
T6 小Biu看電影
不知道爲什麼珂以暴力dfs……
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
using namespace std;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
const int Size=300005;
const int INF=0x3f3f3f3f;
int n,m,cnt,head[Size];
struct Edge {
int v,t,next;
} w[Size<<1];
void AddEdge(int u,int v,int c) {
w[++cnt].v=v;
w[cnt].t=c;
w[cnt].next=head[u];
head[u]=cnt;
}
int ans=INF,val[Size],dis[Size];
void dfs(int x,int sum) {
if(sum>=ans) return;
if(sum+val[x]<ans) {
ans=sum+val[x];
}
for(int i=head[x]; i; i=w[i].next) {
int nxt=w[i].v;
if(sum+w[i].t<dis[nxt]) {
dis[nxt]=sum+w[i].t;
dfs(nxt,sum+w[i].t);
}
}
}
int main() {
// freopen("T6.in","r",stdin);
n=read();
m=read();
for(re i=1; i<=n; i++) {
val[i]=read();
}
for(re i=1; i<=m; i++) {
int u=read();
int v=read();
int c=read()<<1;
AddEdge(u,v,c);
AddEdge(v,u,c);
}
for(re i=1; i<=n; i++) {
memset(dis,0x3f,sizeof(dis));
ans=val[i];
dfs(i,0);
printf("%d\n",ans);
}
return 0;
}
正解:
建一個虛點,從向所有連邊權爲的邊,跑dijkstra。
然後到每個點的距離就是從這個點開始能看到電影的最小花費(容易看出最小花費就是到一個點的最短距離,因爲一開始建了邊權爲的邊)。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<queue>
#define re register int
#define mod 1000000007
using namespace std;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
const int Size=100005;
const int INF=0x3f3f3f3f;
int n,m,cnt,head[Size];
struct Edge {
int v,t,next;
} w[600005];
void AddEdge(int u,int v,int c) {
w[++cnt].v=v;
w[cnt].t=c;
w[cnt].next=head[u];
head[u]=cnt;
}
struct node {
int x,t;
};
inline bool operator < (const node a,const node b) {
return a.t>b.t;
}
int dis[Size];
void Dijkstra(int s) {
memset(dis,0x3f,sizeof(dis));
priority_queue<node> Q;
Q.push((node){s,0});
dis[s]=0;
while(!Q.empty()) {
int x=Q.top().x;
Q.pop();
for(re i=head[x]; i; i=w[i].next) {
int nxt=w[i].v;
if(dis[x]+w[i].t<dis[nxt]) {
dis[nxt]=dis[x]+w[i].t;
Q.push((node){nxt,dis[nxt]});
}
}
}
}
int main() {
// freopen("T6.in","r",stdin);
n=read();
m=read();
int s=n+1;
for(re i=1; i<=n; i++) {
int x=read();
AddEdge(s,i,x);
}
for(re i=1; i<=m; i++) {
int u=read();
int v=read();
int c=read()<<1;
AddEdge(u,v,c);
AddEdge(v,u,c);
}
Dijkstra(s);
for(re i=1; i<=n; i++) {
printf("%d\n",dis[i]);
}
return 0;
}