D. Iterated Linear Function
线性递推。按照我以前的做法,就是矩阵快速幂了。后来我发现,其实这题可以不需要矩阵。递推一下找找规律
x2=a∗x1+b
,
x3=a∗a∗x1+a∗b+b
,
x4=a∗a∗a∗x1+a∗a∗b+a∗b+b
…我们可以发现,
xn
可以看成由两部分组成,前面是
a
的幂乘以
其实还有更简单的方法,就是把快速幂里面的乘法运算,换成”
∗a+b
”就好了。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
ll a,b,x,n;
void fp(){
ll res = x;
while(n){
if(n&1){
res = res * a + b;
res %= mod;
}
b = b * a + b;
b %= mod;
a *= a;
a %= mod;
n>>=1;
}
cout<<res<<endl;
}
int main(){
cin>>a>>b>>n>>x;
fp();
return 0;
}
E. Another Sith Tournament
显然是状压dp。但是比赛的时候我居然没有做出来。。状态应该是这样的,
dp(i,j)
表示还有集合
i
的人还需要比,下场
#include <bits/stdc++.h>
using namespace std;
#define ll long long
double p[22][22];
double dp[1<<18][18];
int bit[1<<18];
//可以递推去计算,每个O(1)
int bit_cnt(int x){
int res = 0;
while(x){
if(x&1){
res++;
}
x>>=1;
}
return res;
}
int who(int x){
int res = 0;
while(x){
res++;
if(x&1){
return res;
}
x>>=1;
}
return 0;
}
vector<int> whos(int x){
vector<int> res;
int cur = 0;
while(x){
cur++;
if(x&1){
res.push_back(cur);
}
x>>=1;
}
return res;
}
bool cmp(int a,int b){
return bit_cnt(a)<bit_cnt(b);
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>p[i][j];
}
}
int End = 1<<n;
for(int i=1;i<End;i++){
bit[i] = i;
}
sort(bit+1,bit+End,cmp);
dp[1][1] = 1;
for(int i=1;i<End;i++){
int b = bit[i];
if((b&1)==0){
continue;
}
vector<int> person = whos(b);
int sz = person.size();
for(int j = 0;j<sz;j++){
for(int k=0;k<sz;k++){
if(j==k)continue;
dp[b][person[j]] = max(dp[b][person[j]],dp[b^(1<<(person[j]-1))][person[k]] * p[person[k]][person[j]] +
dp[b^(1<<(person[k]-1))][person[j]] * p[person[j]][person[k]]);
}
}
}
double ans = 0;
for(int i=1;i<=n;i++){
ans = max(ans,dp[End-1][i]);
}
printf("%.10f\n",ans);
return 0;
}
F. Lena and Queries
首先,最优解的点,肯定出现在上凸壳。但是凸壳是动态的,会增加和删除点,所以我们不能过于频繁去求凸壳,于是分块。对于每块,对之前出现且没被删除的点构造凸壳,排序块内询问,利用单调性在
O(n)
内得解,块内直接暴力。注意实现的时候常数尽量小一点。。。
另外这个题可以用传说中的cdq分治,改天学习一下。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 300010;
const ll INF = 2e18;
int t[maxn];
ll a[maxn];
ll b[maxn];
bool ban[maxn];
ll ans[maxn];
ll ans2[maxn];
struct Point{
ll x,y;
Point(ll x,ll y):x(x),y(y){
}
Point(){
}
bool operator<(const Point &other)const{
if(x!=other.x){
return x<other.x;
}
return y>other.y;
}
};
Point ch[maxn];
pair<Point,int> ppi[maxn];
int sz;
int n;
int k;
void ConvexHull(int end){
sz = 0;
Point pre = Point(-INF,-INF);
for(int i=0;i<k;i++){
Point pt = ppi[i].first;
if(ban[ppi[i].second] || ppi[i].second>end ){
continue;
}
if(pt.x == pre.x){
continue;
}
pre = pt;
if(sz<2){
ch[sz++] = pt;
}else{
while(sz>=2 && (pt.y-ch[sz-1].y)*(ch[sz-1].x-ch[sz-2].x) >=
(ch[sz-1].y-ch[sz-2].y)*(pt.x-ch[sz-1].x) ){
sz--;
}
ch[sz++] = pt;
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&t[i]);
if(t[i] == 1){
scanf("%I64d%I64d",&a[i],&b[i]);
ppi[k++] = make_pair(Point(a[i],b[i]),i);
}else{
scanf("%I64d",&a[i]);
}
ans[i] = ans2[i] = -INF;
}
sort(ppi,ppi+k);
int LEN = sqrt(n);
Point pt_in_block[555];
pair<ll,int> query_in_block[555];
int cntq = 0;
int k = 0;
for(int s=1;s<=n;s+=LEN){
int e = min(n+1,s+LEN);
cntq = 0;
for(int i=s;i<e;i++){
if(t[i] == 3){
for(int j=s;j<e;j++){
if(t[j] == 1 && j < i && !ban[j]){
ans[i] = max(ans[i],b[j]+a[j]*a[i]);
}else if(t[j] == 2 && j > i && a[j] < i){
int aa = a[a[j]];
int bb = b[a[j]];
ans[i] = max(ans[i],bb+aa*a[i]);
}
}
query_in_block[cntq++] = make_pair(a[i],i);
}else if(t[i] == 2){
ban[a[i]] = 1;
}
}
sort(query_in_block,query_in_block+cntq);
ConvexHull(s-1);
if(sz != 0){
int pos = 0;
for(int i=0;i<cntq;i++){
while(pos<sz){
ll val = ch[pos].y + query_in_block[i].first*ch[pos].x;
if( val > ans2[query_in_block[i].second]){
ans2[query_in_block[i].second] = val;
}else{
if(pos){
pos--;
}
break;
}
pos++;
if(pos==sz){
if(pos)pos--;
break;
}
}
}
}
}
for(int i=1;i<=n;i++){
if(t[i] == 3){
ll a = max(ans[i],ans2[i]);
if(a == -INF){
printf("EMPTY SET\n");
}else{
printf("%I64d\n",a);
}
}
}
return 0;
}