• dp


    t1:

    给一个串,问多少子序列构成的数字可以被(3)整除

    (f[i][j])表示前(i)个模(3)余数为(j)的方案数

    现在的+直接继承原来的方案,注意初始化

    int f[N][3]; char s[N];
    int main(){
    	scanf("%s",s + 1);
    	int n = strlen(s + 1);
    	for(int i = 1;i <= n;++i)
    		f[i][(s[i] - '0') % 3] = 1;
    	for(int i = 1;i <= n;++i)
    		for(int j = 0;j < 3;++j)
    			for(int k = i+1;k <= n;++k)
    				f[k][(j + s[k]-'0') % 3] = (f[k][(j+s[k]-'0')%3] + f[i][j]) % mod;
    	for(int i = 1;i <= n;++i)
    		f[0][0] = (f[0][0] + f[i][0]) % mod;
    	printf("%d",f[0][0]);
    	return 0;
    }
    

    t2:

    给你一个合法的括号序列(s1),每次你可以删除一个("()",)你可以删除(0)个或者多个("()"),求能否删成另一个括号序列(s2)

    (f[i][j])表示字符串前(i)个字符删除(())操作,能否匹配到(t)的前(j)个字符

    (s[i]==t[j]),不用删除当前(s[i])(f[i][j]|=f[i-1][j-1])

    (s[i]==)) 尝试删除(s[i])结尾())最小合法字符串序列 假设到(k) (f[i][j]~~|=~~f[k][j])

    bitset<N>f[N];
    int main(){
    	string s,t;
    	cin >> s >> t;
    	int slen = s.size(),tlen = t.size();
    	f[0][0] = 1;
    	for(int i = 1;i <= slen;++i)
    		for(int j = 1;j <= tlen;++j){
    			if(s[i-1] == t[j-1]) f[i][j] = f[i][j] | f[i-1][j-1];
    			if(s[i-1] == ')'){
    				int k = i-1,cnt = 1;
    				while(cnt > 0){
    					if(s[k-1] == ')') ++cnt;
    					else --cnt;
    					--k;
    				}
    				f[i][j] = f[i][j] | f[k][j];
    			}
    		}
    	if(f[slen][tlen]) puts("Possible");
    	else puts("Impossible");
    }
    

    t3:

    Jason 正在打一场 (CF)
    比赛时间为(T)分钟,有(N)道题,可以在比赛时间内的任意时间提交代码
    (i)道题的起始分数为(maxPoints[i]),题目的分数随着比赛的进行,每分钟减少(pointsPerMinute[i])
    这是一场比较(dark)(CF),分数可能减成负数
    已知第(i)道题需要花费 (requiredTime[i])的时间解决
    请问最多可以得到多少分

    第一行输入两个整数(N,T (1 ≤ N ≤ 50, 1 ≤ T ≤ 100000))
    第二行输入(n)个整数(maxPoints[i])
    第三行输入(n)个整数(pointsPerMinute[i])
    第四行输入(n)个整数(requiredTime[i])
    (1 ≤ maxPoints[i],pointsPerMinute[i],requiredTime[i] ≤ 100000)

    1 74
    502
    2
    47
    
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N = 55,T = 1e5 + 5;
    #define int long long
    int f[T];
    struct node{
    	int maxx;//最大分数 
    	int pm;//每分钟减小的分数
    	int re;//需要的时间
    	bool operator < (const node &x) const{
    		return pm*1.0/re > x.pm*1.0/x.re;
    	}
    }e[N]; int n,t;
    signed main(){
    //	freopen("text0.in","r",stdin);
    //	freopen("text0.out","w",stdout);
    	scanf("%lld%lld",&n,&t);
    	for(int i = 1;i <= n;++i) scanf("%lld",&e[i].maxx);
    	for(int i = 1;i <= n;++i) scanf("%lld",&e[i].pm);
    	for(int i = 1;i <= n;++i) scanf("%lld",&e[i].re);
    	sort(e + 1,e + n + 1); int ans = 0;
    	for(int i = 1;i <= n;++i)
    		for(int j = t;j >= e[i].re;--j){
    			f[j] = max(f[j],f[j - e[i].re] + e[i].maxx - e[i].pm*j);
    			ans = max(f[j],ans);
    		}
    	printf("%lld",ans);
    }
    

    t4

    给你一个完全二分图,图中左右两边顶点数相同,每条边染成红绿蓝中一种,满足任意红边不共享端点,任意蓝边不共享端点,求满足条件的染色数 ((nle1e7))

    可以把左右(n)个点的二分图题转化为(n imes n)的棋盘问题,题意转化成在(n imes n)棋盘放红蓝棋子,使任意行列不能有相同颜色棋子方法(但是我没转化qwq)

    我们先默认所有边是绿色的,接下来,我们尝试把一些边染成红蓝色,

    定义(f_i)表示二分图其中一边有(i)个点,并且边只有绿色和红色时的答案。 (f_0=1,f_1=2)

    考虑如何递推,(f_{i-1} o f_i)会新增两个点

    分情况考虑:

    1.这对点只连绿边,方案数为(f_{i-1})

    2.两点连一条红边,现在只能连绿边了,方案数为(f_{i-1})

    3.这对点间连绿边,但至少一个点连了红边

    这对边中的一个点,与之前的一个点之前连了一条红边,那么,其实就相当于还剩(i-1)对待连

    方案数为(2 imes(i-1) imes f(i-1)) (两个点选一个,(i-1)个点对选一对)

    但是我们发现,对于左边和右边连了红边的情况,我们算了两次,所以我们还要减去两边都连红边的情况,减去

    ((i-1)^2 imes f(i-2))

    ((i-1)^2) 意义为各选((i-1))对点

    (f_i=2 imes i imes f(i-1)-(i-1)^2 imes f(i-2))

    再考虑有蓝边的情况,注意到蓝边和红边本质相同,直接容斥即可

    (ans=sumlimits_{k=0}^n(-1)^k(C_n^k)^2i!f(n-k)^2)

    只填一种颜色,对于选取(i)个节点每边都有(large f_n={nchoose i}A_n^i),两边就是((f_n)^2)

    t5

    首先我们肯定是贪心的策略去做,就是我选了叶子节点开始染色,那么染过色的地方就尽量不要去选,这应该是最优策略。
    但其实这样是有错误的
    考虑这样一种情况 (4 o 3 o 2 o 1) 这是其中一条链,假设(k_1=1,k_2=1,k_3=3,k_4=2)
    按照上面的做法,我们从(4)开始染色,ok,(3)(4)已经染色成功,然后继续(2)开始染色,ok,(2)染色成功,最后把根染色这样操作次数要(3)次。其实正确答案应该是(2).
    (4)开始染色,(3)(4)覆盖,(3)染色,(1)(2)覆盖,结束
    所以我们不仅要维护染色的最远距离,同时还需要去更新掉父亲节点的染色距离,
    比如在上述例子,(k[2]=max(k[2],k[3]-1)=k[3]-1=2) 这样就可以避免上述错误了。
    (dfs)维护染色最远距离,并且把子节点的染色范围更新到父亲节点去取最大值即可。
    如果到当前节点无法被子树中节点的染色覆盖,那么就要将当前节点染色。

    int n,ans,f[N]; vector<int>g[N]; int k[N];
    void dfs(int x,int fa){
    	for(int i = 0;i < g[x].size();++i){
    		int v = g[x][i]; dfs(v,x);
    		k[x] = max(k[x],k[v] - 1);//注意k数组,我们不关心这个最远来自谁,只要知道可以最远多少就行了
    		f[x] = max(f[x],f[v] - 1);//还可以往上延申长度
    	}
    	if(!f[x])//如果子节点都无法覆盖到这个点
    		++ans,f[x] = k[x];
    }
    int main(){
    	n = read(); int u;
    	for(int i = 2;i <= n;++i){
    		u = read(); g[u].push_back(i);
    	}
    	for(int i = 1;i <= n;++i) k[i] = read();
    	dfs(1,0); printf("%d",ans);
    }
    
  • 相关阅读:
    poj1179多边形——区间DP
    poj1742硬币——多重背包可行性
    tyvj1061移动服务——DP
    poj1015陪审团——DP+路径记录
    poj3666序列对应——DP
    poj2279排队——杨氏矩阵与钩子公式(DP爆内存)
    tracert
    4 系统的 CPU 使用率很高,但为啥却找不到高 CPU的应用?
    3 当某个应用的CPU使用达到100%,该怎么办?
    2.2 CPU 上下文切换是什么意思?(下)
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13898413.html
Copyright © 2020-2023  润新知