atcoder新手赛261:补题
https://atcoder.jp/contests/abc261/tasksContest 261https://atcoder.jp/contests/abc261/tasks
D:动态规划
硬币正面,cnt值++,价值+a[i]元;
反面,cnt=0,价值不变;
当cnt==c[i]时,价值+y[i];
-
利用:c[x]=y;存当cnt达到某一个值时价值所增加量;
-
dp[i][j]表示:硬币第i次、当下的cnt为j时的最大价值
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)//正面
{
dp[i][j]=dp[i-1][j-1]+a[i]+c[j];//若此时j达不到计数器标准则加0;
}
dp[i][0]=0;//当硬币反面,cnt归0;
for(int k=0;k<i;k++)
{
dp[i][0]=max(dp[i][0],dp[i-1][k]);//枚举从0-i的最大值
}
}//
4.
在所有的dp[n][i]里找到最大值; 记得long long;
E:位运算:按位拆分
输入:n x
n行:t[i],a[i]; 如果t==1,原数x=x&a[i]; t==2,x=x|a[i], t==3,x=x^a[i]; 分别打印n个数,x进行前1个操作后打印,进一步进行前2个操作打印。。。。。
目的:求最终的x;
思路:x,a[i],最多30位,每位初值只能是0、1;先预处理出每位初始分别为0、1时进行前i次操作后的值,就可以很快求出任意数进行前i次操作后的值;为什么只有0-0、1-1两种:
-
对于每一位预处理出每次操作的影响。
-
c(i,j)表示当前位初始值为j(j属于0、1)进行前i次操作后的值;
-
dp(i,j)表示j经过第i次操作后的值;
-
由此得:c(i,0)=dp(c(i-1,0),i,a); c(i,1)=dp(c(i-1,1),i,a);
-
统计答案:用一个变量p表示当前位的值,p初值为题中c该位的值;遍历1-n,当遍历到i时,p=c(i,p) ;累加答案;
#include<bits/stdc++.h> using namespace std; const int N=2e5+5; int n,x; int t[N],a[N],c[N][2],ans[N]; int op(int p,int i,int q) { if(t[i]==1)return p&q; if(t[i]==2)return p|q; if(t[i]==3)return p^q; } int main() { cin>>n>>x; for(int i=1;i<=n;i++) cin>>t[i]>>a[i]; for(int k=0;k<30;k++)//按位进行操作; { c[1][0]=op(0,1,a[1]>>k&1); c[1][1]=op(1,1,a[1]>>k&1);//预处理首位 for(int i=2;i<=n;i++) { c[i][0]=op(c[i-1][0],i,a[i]>>k&1); c[i][1]=op(c[i-1][1],i,a[i]>>k&1);//预处理 } int p=x>>k&1;//初始 0、1; for(int i=1;i<=n;i++) { p=c[i][p]; ans[i]+=(p<<k); } } for(int i=1;i<=n;i++) cout<<ans[i]<<endl; return 0; }
F:树状数组
题目:n个球,属性:颜色、数字;对相邻的两个球进行交换时,若颜色不同,花费代价1,求:将球排成数字不降序的顺序时,所花费的最小代价;
思路:所求的最小代价即是颜色不同的逆序对数量;则:求不考虑颜色时的逆序对数量减去对各个颜色,
颜色相同的逆序对数量;求逆序对:使用树状数组;
#include<bits/stdc++.h> using namespace std; const int N=3e5+10; #define ll long long ll c[N]; ll tree[N],n; vector<int>v[N]; int lowbit(int x) { return x&(-x); } void add(int x,int c) { for(int i=x;i<=n;i+=lowbit(i)) { tree[i]+=c; } } ll sum(int x) { ll res=0; for(int i=x;i;i-=lowbit(i)) res+=tree[i]; return res; } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>c[i]; for(int i=1;i<=n;i++) { int x; cin>>x; v[0].push_back(x);//存储不考虑颜色的值求不考虑颜色时的逆序对 v[c[i]].push_back(x);//存储考虑颜色时的值求考虑相同颜色的逆序对 } ll ans=0; for(int i=0;i<=n;i++) { for(auto& x:v[i]) { ans=ans+(i?-1:1)*(sum(n)-sum(x)); add(x,1); } for(auto& x:v[i]) add(x,-1);//在相同颜色中找到逆序对; } cout<<ans<<endl; return 0; }