zoukankan      html  css  js  c++  java
  • 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);
    }
    
  • 相关阅读:
    VC 常见问题百问
    python windows 环境变量
    Check server headers and verify HTTP Status Codes
    Where are the AES 256bit cipher suites? Please someone help
    outlook 如何预订会议和会议室
    安装Axis2的eclipse插件后,未出现界面
    windows 环境变量
    python 时间日期处理汇集
    openldap学习笔记(使用openldap2.3.32)
    set p4 environment in windows
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13898413.html
Copyright © 2011-2022 走看看