A
题意:罗里吧嗦,什么开始时候有a和b两种人,a这种人每过一秒会把右边如果是b种人就会把他变成a,
不就是求A后面的P最长连续有几个?
int n; char s[200005]; void test_case() { scanf("%d%s", &n, s + 1); int cnt = 0, ans = 0; int b = 1; while(b <= n && s[b] == 'P') ++b; for(int i = b; i <= n; ++i) { if(s[i] == 'P') ++cnt; else { ans = max(ans, cnt); cnt = 0; } } ans = max(ans, cnt); printf("%d ", ans); }
B - Hyperset
题意:每个属性只有3种值。定义三张牌是一个SET,
aaaa
bbbb
cccc
每一列的的字母当他们要么全等要么两两不同。
题解:枚举两张牌,可以确定第三张牌,放到
unordered_map里面查找
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int n,m; cin>>n>>m; unordered_map<string,int> qwq; qwq.clear(); string s[n+1]; for(int i=0;i<n;++i){ cin>>s[i]; qwq[s[i]]=i+1; } int ans=0; for(int i=0;i<n-2;++i) for(int j=i+1;j<n-1;++j){ string ss; for(int k=0;k<m;++k){ if (s[i][k]==s[j][k]) ss+=s[i][k]; else if (s[i][k]!='S'&&s[j][k]!='S') ss+='S'; else if (s[i][k]!='T'&&s[j][k]!='T') ss+='T'; else if (s[i][k]!='E'&&s[j][k]!='E') ss+='E'; } if (qwq[ss]>j) ++ans; } cout<<ans<<endl; return 0; }
C
心模拟了半天,最后放弃了
题意
给你一串从1−n 1-n1−n的序列,其中部分未知(表示为0),补全序列使得相邻数值奇偶性相反的数量最少
相邻数值的奇偶性相反:两个相邻的两个数值,其中一个为奇数另外一个为偶数
分析
一开始用了贪心,结果卡在第十二个样例,然后改成dp
定义dp数组如下
int dp[120][60][2];
dp[i][j][0/1] 表示第i+1个位置放了偶/奇数,且到第i+1处总共放了j个奇数,有多少个奇偶性相反
1
2
得到状态转移方程
dp[i][j][1] = min(dp[i - 1][j - 1][0] + 1, dp[i - 1][j - 1][1]);
dp[i][j][0] = min(dp[i - 1][j][1] + 1, dp[i - 1][j][0]);
1
2
当然这得看这个位置本身是不是已经有了数值,如果为0则两个都需要,如果已经有数值了就按照原来的数值进行dp
#include <bits/stdc++.h> using namespace std; void solve() { int n; int dp[120][60][2], v[120]; cin>>n; for(int i=0;i<n;++i) { cin >> v[i]; } memset(dp, 0x3f, sizeof(dp)); if(v[0] == 0) dp[0][1][1] = dp[0][0][0] = 0; else dp[0][v[0] & 1][v[0] & 1] = 0; for (int i = 1; i < n; ++i) { for (int j = 0; j <= min(i + 1, (n + 1) / 2); ++j) { if ((v[i] & 1 || v[i] == 0) && j > 0) dp[i][j][1] = min(dp[i - 1][j - 1][0] + 1, dp[i - 1][j - 1][1]); if (!(v[i] & 1)) dp[i][j][0] = min(dp[i - 1][j][1] + 1, dp[i - 1][j][0]); } } cout << min(dp[n-1][(n+1)/2][1], dp[n-1][(n+1)/2][0]) << endl; } int main() { solve(); return 0; }
D
给出一棵有根树,每个节点都有一个权值,代表的是在其子树中有多少个节点的val比他小,现在要求根据每个点的权值构造出1~n的val数列
输入,p,c;p表示该点的父亲在第p层,c表示该点的子树里面c个小于该点的值。
思路:
首先证明:n个节点一定可以用1-n的数字去放。因为1-n的数字都是不同的,那么不会有相对大小的问题,不会有节点之间相互影响而导致答案错误。放相同值的节点也就是少一个差值,我们完全可以用放的方式去避免,比如小的放在大的上面。
其次证明:如果节点的C值小于节点的size(这个点包括他的子树总共有多少个点),那么一定存在这种方案,所以出现c值大于节点size肯定是不存在的。
我们从顶点开始放,因为我们放1到n的数字,那么有多少个数字没放是一定的,所以我们相当于是从没放的数字当中找第C+1大的数字放上去,然后标记放的数字,向下递归。一定满足。
#include<bits/stdc++.h> #define TEST freopen("C:\Users\hp\Desktop\ACM\in.txt","r",stdin); #define mem(a,x) memset(a,x,sizeof(a)) #define debug(x) cout << #x << ": " << x << endl; #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int mod=1e9+7; const int maxn = 1e6+5; int n; vector<int>edge[maxn]; int ans[maxn],c[maxn],vis[maxn],siz[maxn]; void dfs(int u) { siz[u]=1; int sum=0,k; for(int i=1;i<=n;i++) { if(!vis[i]) sum++; if(sum==c[u]+1) { k=i; break; } } ans[u]=k; vis[k]=1; for(auto to:edge[u]) { int v=to; dfs(v); siz[u]+=siz[v]; } if(c[u]>siz[u]-1) { cout<<"NO "; exit(0); } } int main() { int root=0; cin>>n; for(int i=1;i<=n;i++) { int fa; cin>>fa>>c[i]; if(fa==0) root=i; else edge[fa].push_back(i); } dfs(root); cout<<"YES "; for(int i=1;i<=n;i++) { cout<<ans[i]<<" "; } cout<<" "; }