T1
一道0,1背包的题。。看这个数是否放入背包。。。
这个是标程
/*
选出来的每个整数相当于重量w[i];每个整数的因数和相当于价值c[i]
背包最大容量为s;
f[i][x]表示考虑了前i个数,当前得到的和为x时(背包已装容量),得到的因数和(价值)最大值
*/
#include <bits/stdc++.h>
using namespace std;
int m,s,f[1005][1005];
int ysh[1005]; //ysh[i]表示i的因数和,可以先预处理出来
void makesum(int m) //求出1...m每个数的因数和
{
ysh[1]=0;
for(int i=2;i<=m;i++)
{
s=1;
for(int j=2;j<=i/2;j++)
if(i%j==0) s=s+j;
ysh[i]=s;
}
}
int main()
{
freopen("sum.in", "r", stdin);
freopen("sum.out", "w", stdout);
scanf("%d", &m);
makesum(m); //预处理1...m每个数的因数和
memset(f,0,sizeof(f));
for(int i=1; i<=m;++i) // 0/1背包
for(int x=1;x<=m;x++)
if(x>=i)
f[i][x]=max(f[i-1][x-i]+ysh[i],f[i-1][x]); //第i个数可以选择装进背包
else
f[i][x]=f[i-1][x]; //第i个数不能装进背包
printf("%d\n",f[m][m]);
return 0;
}
这个是打表代码
/*
选出来的每个整数相当于重量w[i];每个整数的因数和相当于价值c[i]
背包最大容量为s;
f[i][x]表示考虑了前i个数,当前得到的和为x时(背包已装容量),得到的因数和(价值)最大值
*/
#include <bits/stdc++.h>
using namespace std;
int m,f[1005][1005];
const int ysh[1001] = {0, 0, 1, 1, 3, 1, 6, 1, 7, 4, 8, 1, 16, 1, 10, 9, 15, 1, 21, 1, 22, 11, 14, 1, 36, 6, 16, 13, 28, 1, 42, 1, 31, 15, 20, 13, 55, 1, 22, 17, 50, 1, 54, 1, 40, 33, 26, 1, 76, 8, 43, 21, 46, 1, 66, 17, 64, 23, 32, 1, 108, 1, 34, 41, 63, 19, 78, 1, 58, 27, 74, 1, 123, 1, 40, 49, 64, 19, 90, 1, 106, 40, 44, 1, 140, 23, 46, 33, 92, 1, 144, 21, 76, 35, 50, 25, 156, 1, 73, 57, 117, 1, 114, 1, 106, 87, 56, 1, 172, 1, 106, 41, 136, 1, 126, 29, 94, 65, 62, 25, 240, 12, 64, 45, 100, 31, 186, 1, 127, 47, 122, 1, 204, 27, 70, 105, 134, 1, 150, 1, 196, 51, 74, 25, 259, 35, 76, 81, 118, 1, 222, 1, 148, 81, 134, 37, 236, 1, 82, 57, 218, 31, 201, 1, 130, 123, 86, 1, 312, 14, 154, 89, 136, 1, 186, 73, 196, 63, 92, 1, 366, 1, 154, 65, 176, 43, 198, 29, 148, 131, 170, 1, 316, 1, 100, 141, 203, 1, 270, 1, 265, 71, 104, 37, 300, 47, 106, 105, 226, 31, 366, 1, 166, 75, 110, 49, 384, 39, 112, 77, 284, 31, 234, 1, 280, 178, 116, 1, 332, 1, 202, 153, 218, 1, 312, 53, 184, 83, 194, 1, 504, 1, 157, 121, 190, 97, 258, 33, 232, 87, 218, 1, 476, 35, 130, 177, 255, 1, 270, 45, 328, 129, 134, 1, 456, 59, 214, 93, 208, 1, 450, 1, 286, 175, 140, 97, 396, 1, 142, 137, 440, 1, 294, 1, 220, 195, 218, 49, 531, 18, 250, 101, 226, 1, 390, 65, 274, 183, 152, 37, 568, 51, 154, 105, 316, 67, 396, 1, 364, 107, 266, 1, 528, 1, 160, 309, 244, 1, 330, 41, 442, 111, 254, 37, 523, 109, 166, 113, 302, 55, 534, 1, 256, 161, 170, 73, 656, 1, 211, 117, 416, 43, 438, 57, 316, 231, 176, 1, 492, 1, 394, 209, 404, 1, 366, 77, 274, 219, 182, 1, 810, 20, 184, 169, 420, 79, 378, 1, 376, 177, 314, 61, 524, 1, 274, 249, 344, 43, 582, 1, 460, 131, 194, 1, 636, 191, 196, 185, 298, 1, 618, 41, 463, 135, 200, 85, 696, 1, 202, 241, 561, 1, 414, 45, 310, 321, 314, 49, 672, 1, 346, 141, 316, 67, 522, 89, 466, 143, 302, 1, 924, 1, 214, 201, 386, 133, 438, 69, 328, 243, 362, 1, 808, 1, 334, 285, 334, 43, 450, 1, 640, 300, 314, 1, 620, 95, 226, 153, 568, 1, 759, 53, 346, 155, 230, 217, 744, 1, 232, 261, 548, 1, 690, 1, 466, 303, 236, 1, 806, 75, 394, 161, 428, 55, 486, 145, 532, 225, 242, 1, 1032, 51, 244, 285, 447, 103, 606, 1, 442, 167, 536, 1, 684, 47, 346, 441, 496, 79, 510, 1, 592, 171, 254, 1, 1056, 107, 358, 225, 388, 1, 786, 81, 511, 287, 260, 109, 716, 59, 394, 177, 740, 1, 648, 1, 400, 467, 266, 49, 960, 24, 442, 249, 588, 55, 546, 113, 484, 183, 272, 145, 1140, 1, 274, 185, 590, 115, 798, 1, 418, 257, 566, 49, 888, 87, 280, 357, 424, 1, 690, 57, 928, 303, 284, 1, 780, 119, 286, 401, 512, 1, 870, 1, 604, 195, 434, 169, 1075, 1, 343, 197, 680, 91, 594, 65, 526, 507, 296, 1, 1008, 51, 490, 201, 586, 1, 846, 269, 454, 203, 410, 1, 1260, 1, 454, 281, 460, 193, 618, 1, 652, 351, 506, 61, 1026, 1, 310, 393, 824, 1, 630, 1, 724, 339, 314, 97, 1112, 156, 316, 333, 478, 55, 1242, 1, 568, 215, 320, 133, 876, 161, 442, 297, 890, 1, 654, 1, 700, 411, 434, 1, 1167, 71, 652, 373, 496, 1, 666, 137, 646, 305, 494, 1, 1356, 1, 334, 345, 596, 295, 816, 53, 508, 227, 554, 73, 1344, 1, 340, 565, 605, 1, 690, 105, 940, 231, 470, 1, 1136, 143, 514, 233, 676, 67, 1038, 1, 526, 555, 350, 145, 1104, 59, 352, 237, 1036, 1, 978, 57, 820, 447, 356, 109, 972, 1, 586, 329, 638, 55, 1014, 293, 544, 243, 362, 1, 1698, 111, 421, 245, 550, 205, 870, 1, 952, 364, 602, 61, 1004, 1, 370, 633, 776, 79, 900, 1, 856, 379, 554, 1, 1176, 155, 376, 345, 764, 115, 1122, 1, 736, 255, 506, 157, 1484, 1, 382, 393, 1040, 1, 774, 117, 580, 639, 386, 73, 1276, 1, 958, 261, 586, 1, 942, 217, 694, 439, 392, 61, 1572, 83, 514, 417, 983, 163, 798, 1, 598, 267, 650, 121, 1548, 75, 400, 501, 604, 1, 1122, 65, 1153, 369, 404, 85, 1100, 347, 538, 273, 722, 1, 1368, 1, 868, 275, 554, 169, 1416, 63, 412, 637, 944, 1, 834, 1, 736, 663, 614, 1, 1356, 1, 682, 281, 946, 193, 846, 173, 844, 443, 422, 1, 2040, 30, 424, 285, 640, 253, 1026, 217, 826, 287, 824, 61, 1164, 1, 634, 705, 764, 1, 1158, 1, 988, 483, 434, 1, 1656, 179, 436, 361, 924, 91, 1290, 81, 778, 401, 566, 373, 1196, 1, 442, 297, 1352, 1, 1341, 1, 880, 555, 446, 1, 1392, 135, 730, 561, 676, 67, 906, 185, 1144, 447, 452, 61, 1921, 71, 610, 505, 806, 187, 918, 1, 688, 417, 1106, 1, 1568, 95, 460, 573, 694, 139, 1242, 1, 1240, 311, 464, 85, 1764, 253, 466, 425, 962, 1, 1374, 209, 706, 315, 470, 361, 1794, 1, 694, 317, 1076, 1, 954, 65, 916, 975, 638, 1, 1292, 87, 910, 321, 1208, 1, 1152, 197, 724, 483, 482, 145, 2088, 32, 634, 441, 730, 199, 1338, 1, 1027, 471, 794, 1, 1576, 147, 490, 761, 946, 1, 990, 101, 1414, 449, 494, 1, 1536, 203, 634, 549, 972, 67, 1818, 1, 1024, 335, 734, 205, 1356, 1, 502, 521, 1340};
//ysh[i]表示i的因数和,先打表打出每个整数的因数和
int main()
{
freopen("sum.in", "r", stdin);
freopen("sum.out", "w", stdout);
f[0][0]=0;
scanf("%d", &m);
for(int i=1; i<=m;++i) // 0/1背包
for(int x=1;x<=m;x++)
if(x>=i)
f[i][x]=max(f[i-1][x-i]+ysh[i],f[i-1][x]); //第i个数可以选择装进背包
else
f[i][x]=f[i-1][x]; //第i个数不能装进背包
printf("%d\n",f[m][m]);
return 0;
}
这个是我的代码(所以我都不知道我的dp是什么意思。。。居然是一维的我惊了)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define rg register
using namespace std;
inline int read()
{
int 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*10+ch-'0';
ch=getchar();
}
return x*f;
}
int f[1010];
int tag[1010][1010];
int yinshu[1010][1010];
int flag[1010];
int n;
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
n=read();
f[1]=0;f[2]=1;
tag[2][1]=1;
for(rg int i=1;i<=n;i++)
yinshu[i][1]=1;
for(rg int i=2;i<=n;i++)
{
yinshu[i][i]=1;
for(rg int j=i*2;j<=n;j+=i)
yinshu[j][i]=1;
}
for(rg int i=3;i<=n;i++)
{
int a[2]={0,0},b[3]={0,0,0},c[3]={0,0,0};
for(rg int j=1;j<i;j++)
{
/*
if(f[j]>f[i])
for(int k=1;k<=j;k++)
tag[i][k]=tag[j][k];
f[i]=max(f[i],f[j]);
*/
if (f[j]>a[0])
a[0]=j,a[1]=f[j];
}
for(rg int j=1;j<i;j++)
{
int k=i-j;
if(k==j || tag[j][k])
continue;
int sum=0;
for(rg int nm=1;nm<=k/2;nm++)
sum+=(yinshu[k][nm]*nm);
if(f[j]+sum>b[2])
{
b[0]=j;b[1]=k;b[2]=f[j]+sum;
// for(int nm=1;nm<=j;nm++)
// tag[i][nm]=tag[j][nm];
// tag[i][k]++;
}
// f[i]=max(f[i],f[j]+f[k]);
}
int sum=0;
for(rg int j=1;j<i;j++)
sum+=(yinshu[i][j]*j);
if(sum>f[i])
{
c[0]=i;c[1]=sum;
}
if(c[1]>=b[2] && c[1]>=a[1])
tag[i][c[0]]++,f[i]=c[1];
else if(a[1]>=c[1] && a[1]>=b[2])
{
for(rg int k=1;k<=a[0];k++)
tag[i][k]=tag[a[0]][k];
f[i]=a[1];
}
else
{
for(rg int nm=1;nm<=b[0];nm++)
tag[i][nm]=tag[b[0]][nm];
tag[i][b[1]]++;
f[i]=b[2];
}
// f[i]=max(f[i],sum);
}
printf("%d",f[n]);
}
T2
这道题首先二分答案(即平均值) 然后判断这个答案是否合法
如果合法则继续向上二分 否则向下二分
这个都很好理解
关键是如何判断合法呢 这里是采用了单调队列
首先把每个数减去当前的平均值后求出前缀和
枚举右端点i 则左端点的范围为i-L~i-R
然后使用一个递增的单调队列 如果队首不在范围内 就弹出
如果队尾大于正要加入的数 就弹出,直到小于等于
如果当前i节点的前缀和-队首的值>0,返回true,否则返回false
(这里就可以理解为什么要维护递增的单调区间了,因为要减去尽量小的值,这个式子总体的值才大)
这个样子就可以了
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
const double eps=1e-9;
const int maxn=1e5;
int n,l,r;
double maxa,a[maxn],b[maxn],c[maxn];
int read()
{
int 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*10+ch-'0';
ch=getchar();
}
return x*f;
}
bool check(double x)
{
double sum[maxn],que[maxn];
int head=1,tail=0,pos[maxn];
for(int i=1;i<=n;i++)
sum[i]=a[i]+sum[i-1]-x;
for(int i=l;i<=n;i++)
{
while(head<=tail && que[tail]>=sum[i-l])
tail--;
while(head<=tail && pos[head]+r<i)
++head;
que[++tail]=sum[i-l];
pos[tail]=i-l;
if(sum[i]-que[head]>=0)
return true;
}
return false;
}
int main()
{
n=read();l=read();r=read();
for(int i=1;i<=n;++i)
{
scanf("%lf",&a[i]);
if(a[i]-maxa>eps)
maxa=a[i];
}
double l=0,r=maxa,ans;
while(r-l>eps)
{
double mid=(l+r)/2;
if(check(mid))
{
ans=mid;
l=mid;
}
else
{
r=mid;
}
}
printf("%.4f",ans);
}
T3
这道题相当于找一个最小生成树,再加边使得有n个点n条边,这样就可以保证每个点入度都为1
使用kruskal算法,因为这个算法是先加入边权较小的边
注意这个题有可能是基环树森林哦,所以我们需要判断每个点它(它父亲)所在的树是否有环
如果当前正要加入的边连接了两个有环树 continue
如果当前加入的边在一个树内 就会形成一个有环树
如果是连接两个无环树 没有影响
如果连接一个无环树 一个有环树 就会形成一棵有环树
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
using namespace std;
const int maxn=5*1e5+100;
struct node{
int from,to,val;
inline bool operator <(const node &x)const{
return val<x.val;
}
#define from(x) edge[x].from
#define to(x) edge[x].to
#define val(x) edge[x].val
}edge[maxn];
int n,m,par[maxn],ring[maxn];
int read()
{
int 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*10+ch-'0';
ch=getchar();
}
return x*f;
}
int getfather(int x)
{
if(par[x]==x) return x;
ring[par[x]]=max(ring[par[x]],ring[x]);
par[x]=getfather(par[x]);
return par[x];
}
signed main()
{
n=read();m=read();
for(int i=1;i<=m;i++)
{
from(i)=read();to(i)=read();val(i)=read();
}
sort(edge+1,edge+1+m);
int f1,f2,ans=0;
for(int i=1;i<=n;i++) par[i]=i;
for(int i=1;i<=m;i++)
{
f1=getfather(from(i));
f2=getfather(to(i));
if(ring[f1] && ring[f2])//如果两棵树都是有环树,则跳过,因为如果再加边就会使得每个边的入度大于1
continue;
if(f1==f2 || ring[f1] || ring[f2])//在一个联通块内加边会形成环,一个无环树与一个有环树形成一个有环树
ring[f1]=ring[f2]=1;
ans+=val(i);
par[f1]=f2;
}
printf("%lld",ans);
}
在然后就是可爱的费用流了(费用流会爆空间,只能得60分,呜呜呜100多行呢考试的时候写了,我好难受只有60分)
(疯狂暗示这是考试代码)
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#define int long long
using namespace std;
const int maxn=850100;
const int inf=0x3f3f3f3f;
int first[maxn<<1],next[maxn<<1],to[maxn<<1],flow[maxn<<1],cost[maxn<<1];
int tot=1;
int n,m,s,t;
int d[maxn<<1],maxflow,ans,book[maxn<<1],pre[maxn<<1];
int incf[maxn<<1],x,y,c;
int read()
{
int 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*10+ch-'0';
ch=getchar();
}
return x*f;
}
void add(int u,int v,int w,int f)
{
tot++;
next[tot]=first[u];
first[u]=tot;
to[tot]=v;
flow[tot]=w;
cost[tot]=f;
}
bool spfa()
{
queue<int> q;
memset(book,0,sizeof(book));
for(int i=1;i<=n+m+1;i++)
d[i]=inf;
q.push(s);
d[s]=0;book[s]=1;incf[s]=0x3f3f3f3f;
while(!q.empty())
{
int x=q.front();
book[x]=0;
q.pop();
for(int i=first[x];i;i=next[i])
{
int y=to[i];
if(flow[i] && d[y]>d[x]+cost[i])
{
d[y]=d[x]+cost[i];
incf[y]=min(incf[x],flow[i]);
pre[y]=i;
if(book[y]==0) book[y]=1,q.push(y);
}
}
}
if(d[t]==inf)
return false;
return true;
}
void update()
{
int cxk=t;
while(cxk!=s)
{
int i=pre[cxk];
flow[i]-=incf[t];
flow[i^1]+=incf[t];
cxk=to[i^1];
}
maxflow+=incf[t];
ans=ans+d[t]*incf[t];
}
signed main()
{
freopen("trade.in","r",stdin);
freopen("trade.out","w",stdout);
n=read();m=read();
s=0;t=n+m+1;
for(int i=1;i<=m;i++)
{
add(s,i,1,0);
add(i,s,0,0);
x=read();y=read();c=read();
add(i,x+m,1,c);
add(x+m,i,0,-c);
add(i,y+m,1,c);
add(y+m,i,0,-c);
}
for(int i=1;i<=n;i++)
{
add(i+m,t,1,0);
add(t,i+m,0,0);
}
while(spfa()) update();
if(maxflow==n)
printf("%lld",ans);
else printf("No");
return 0;
}