http://acm.hdu.edu.cn/showproblem.php?pid=6763
很明显的对于一个连通块需要执行其中点权值最小的那个,连通块也可能分裂, 只要每次找个连通块反复删最小的权值即可,但这种情况不好实现,所以换下面这种方法
从最大权值的点倒着添加边,也就是新增点时,小权值点向一个大权值点连接边时,小取值需要的变成0的次数可以由大权值的点承担(因为连通,在减大权值的时候小权值一起减)。
1、对输入的点按照权值非递减排序,并且初始化存边的容器,初始化集合,初始化vis。
2、出现小权值可以到达大权值的情况时,将两者归为一类, a n s − = ans-= ans−=权值
#include
#include
#include
#include
#include
using namespace std;
#define INF 0x3f3f3f3f
const int N=1e5 + 9;
pair<int,int>p[N]; //存存点和并查集的值
vector<int>g[N]; //存边
int T, n, m, u, v;
long long ans;
int f[N], vis[N];
int fd(int u){
if(f[u]==u) return u;
return f[u]=fd(f[u]);
}
void link(int u, int v){
int uu=fd(u), vv=fd(v);
if(uu!=vv)
f[uu]=vv;
return ;
}
void solve(){
scanf("%d %d", &n, &m);
for(int i=1; i<=n; i++){
scanf("%d", &p[i].first), p[i].second=i;
g[i].clear(), f[i]=i, vis[i]=0;
}
for(int i=1; i<=m; i++){
scanf("%d %d", &u, &v);
g[u].push_back(v), g[v].push_back(u);
}
sort(p+1, p+1+n);
ans=0;
for(int i=n; i>=1; i--){
ans+=p[i].first;
u=p[i].second;
for(int it: g[u]) //遍历可到达的点
if(vis[it]) //可到达点在该点之前(权值比该点大)
if(fd(it)!=fd(u)) //两者不在同一集合
link(u, it), ans-=p[i].first; //连通两点,该点删除的次数由大权值点承担
vis[u]=1;
}
printf("%lld\n", ans);
return ;
}
int main(){
scanf("%d", &T);
while(T--) solve();
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=6768
原本A*B=C,但C的一位1被改成了0,所以 A + B = C + f [ k ] A+B=C+f[k] A+B=C+f[k],变换一下 f [ k ] = A + B − C f[k]=A+B-C f[k]=A+B−C,所以可以直接暴力求A,B,C的数,因为斐波那契数在这里非常大,所以需要使用哈希,但是这里可以神奇的直接用2^64当作模数,也就是unsigned long long,所有不需要取模,它的取模自然溢出就当取模了(从0开始的)。
#include
#include
using namespace std;
typedef unsigned long long ull;
const int N=2e6 + 9;
ull a, b, c;
int idx;
ull f[N];
void init(){ //斐波那契打表
f[1]=1ull, f[2]=2ull;
for(ull i=3; i<=N; i++) f[i]=f[i-1]+f[i-2];
return ;
}
ull write(){ //暴力求A,B,C
int x, step;
ull ans=0;
cin>>x;
for(ull i=1; i<=x; i++){
cin>>step;
if(step==1) ans+=f[i];
}
return ans;
}
void solve(){
a=write();
b=write();
c=write();
ull temp=a*b-c; //求f[k]
for(ull j=1; ; j++){
if(f[j]==temp) {idx=j; break;} //求变化的那个斐波那契的位置
}
cout<<idx<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
init();
int T;
cin>>T;
while(T--) solve();
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=6772
直接暴力DFS,每种类型往下面深搜就完事了
#include
#include
#include
#include
using namespace std;
// #define TDS_ACM_LOCAL
const int N=59;
typedef long long ll;
struct node
{
ll a, b, c, d;
};
vector<node>v[N];
int n, m, k, sum;
int vis[N];
ll a, b, c, d;
void init(){
sum=0;
for(int i=1; i<=m; i++) vis[i]=0, v[i].clear();
return ;
}
ll dfs(int k, ll a, ll b, ll c, ll d){
if(k==sum+1) //到底了就return答案
return (100ll + a)*(100ll + b)*(100ll + c)*(100ll +d);
ll ans=0;
for(auto it: v[k]) //遍历该种类型,然后深搜
ans=max(ans, dfs(k+1, a+it.a, b+it.b, c+it.c, d+it.d));
return ans;
}
void solve(){
cin>>n>>m;
init(); //初始化一下容器之类的
for(int i=0; i<n; i++){
cin>>k>>a>>b>>c>>d;
if(!vis[k]) vis[k]= ++sum; //记录种类和种类个数
v[vis[k]].push_back({a,b,c,d}); //按照记录的种类存
}
ll ans=dfs(1, 0, 0, 0, 0);
cout<<ans<<endl;
return ;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#ifdef TDS_ACM_LOCAL
freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
int T;
cin>>T;
while(T--) solve();
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=6774
1、预处理 a a a串中每个字符第一次出现的位置
2、每次查询区间时,dp表示查询区间第i位是b串的j位时,对应的a的位置,且 < = r i g h t <=right <=right
#include
#include
#include
#include
#include
using namespace std;
#define INF 0x3f3f3f3f
const int N=1e5 + 9;
char a[N], b[30];
int lena, lenb;
int loc[N][30], dp[30][30];
int T, TT, l, r, mx, ans;
void init(){
scanf("%s %s", a+1, b+1);
lena=strlen(a+1), lenb=strlen(b+1);
for(int i=0; i<26; i++) loc[lena][i]=INF; //初始化出现的位置
//记录a中每个字符第一次出现的位置(从后往前记录,方便每次遇到相同的覆盖上一次
for(int i=lena-1; i>=0; i--){
for(int j=0; j<26; j++) loc[i][j]=loc[i+1][j]; //将后面存好的行放进当前行,因为数组a从后往前匹配的
loc[i][a[i+1]-'a']=i+1; //将该当前的字符出现的位置记录
}
}
void solve(){
init();
scanf("%d" , &TT);
while(TT--){
scanf("%d %d", &l, &r);
ans=0;
memset(dp, INF, sizeof(dp)); //dp表示查询区间第i位是b串的j位时,对应的a的位置
for(int j=1; j<=lenb; j++) dp[1][j]=loc[l-1][b[j]-'a']; //将查询区间的最左边存入dp
for(int i=1; i<=lenb; i++){
for(int j=1; j<=lenb; j++){
if(dp[i][j]<=r){ //合理位置
ans=max(ans, i); //最长匹配长度
for(int k=j+1; k<=lenb; k++)
dp[i+1][k]=min(dp[i+1][k], loc[dp[i][j]][b[k]-'a']); //计算后面一行
}
}
}
ans=(r-l+1-ans)+(lenb-ans);
printf("%d\n", ans);
}
return ;
}
int main(){
scanf("%d", &T);
while(T--) solve();
return 0;
}