Codeforces Round #549 (Div. 1) C&D&E
C
把x方減去,bx+c 就是個一次函數,然後發現上方沒有點的限制相當于這個直線上方沒有點,是以是個凸包
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+5;
struct Node{
ll x,y;
Node(ll x = 0,ll y = 0) : x(x), y(y) {}
long double operator * (const Node b)const{
return (long double)y*b.x - (long double)x*b.y;
}
Node operator - (const Node b)const{
return Node(this->x - b.x,this->y - b.y);
}
bool operator < (const Node b) const {
return x==b.x ? y<b.y : x < b.x;
}
}t[N];
int n;
Node stk[N];int top;
int main()
{
cin >> n;
for(int i=1;i<=n;i++){
ll x,y;cin >> x >> y;
t[i] = Node(x,y-x*x);
}
sort(t+1,t+n+1);
for(int i=1;i<=n;i++){
if(t[i].x == t[i+1].x && i!=n) continue;
while(top>=2 && 0 >= (stk[top]-stk[top-1]) * (t[i]-stk[top-1]))--top;
stk[++top] = t[i];
}
cout << top-1 << endl;
return 0;
}
D
關鍵在于對于順序的轉移,考慮如何構造出所有小于他的數。
對 x , t = x/10 ,我們用所有的 < t 的數加上所有能夠加的,再加上1 - 9 , 然後再把t上比他小的加上去就構造出所有比它小的了,然後發現%11 = 0 ~ 10 生成的數加起來mod 11 == 0,于是隻用記錄%11的餘數預處理轉移就行了。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n;
char s[N];
int t[12][12];
typedef long long ll;
ll f[N][12];
ll ans = 0;
int main()
{
scanf("%s",s+1);
n = strlen(s+1);
for(int i=0;i<=10;i++){
int pre = i-1;pre = pre < 0 ? pre+11:pre;
for(int digit=0;digit<i;digit++){
t[i][digit] = 9 + pre*(pre+1)/2 + digit + 1;
t[i][digit] %= 11;
}
}
for(int i=1;i<=n;i++){
int c = s[i]-'0';
for(int j=c+1;j<=10;j++)
f[i][t[j][c]] += f[i-1][j];
if(c!=0)f[i][c]++;
for(int j=0;j<=10;j++) ans+=f[i][j];
}
cout << ans << endl;
}
E
先看m=0的情況,很容易構造出每次拓展一個點根據方向換根最後成一顆樹。
然後發現我們現在需要解決的就是拓展點的時候找不到邊的情況。
發現隻要它不能到達的點都已經在目前的樹裡面就可以做了,那每個沒入度的分量随便選一個點。每次一個點(不是根)在樹裡面,要麼再在這個分量取一個,要麼這個分量沒了把邊删掉沒入度的加進去就行了。
include<bits/stdc++.h>
using namespace std;
int query(int x,int y){
printf("? %d %d\n",x,y);
fflush(stdout);
int ans; scanf("%d",&ans);
return ans;
}
const int N=2e5+5;
int hed[N],from[N],to[N],nxt[N],cnt;
int deg[N];
inline void adde(int u,int v){
++cnt;from[cnt]=u,to[cnt]=v,nxt[cnt]=hed[u];hed[u]=cnt;
}
int dfn[N],low[N],num,stk[N],top,col[N],cn;
vector<int> scc[N];
int n,m;
inline void tarjan(int x){
dfn[x] = low[x] =++num;
stk[++top] = x;
for(int i=hed[x];i;i=nxt[i]){
int v=to[i];
if(!dfn[v]){
tarjan(v);
low[x] = min(low[x], low[v]);
}else if(!col[v])low[x] = min(low[x],dfn[v]);
}
if(low[x]==dfn[x]){
++cn;
while(stk[top]!=x){
scc[cn].push_back(stk[top]);
col[stk[top--]] = cn;
}
scc[cn].push_back(stk[top]);
col[stk[top--]] = cn;
}
}
queue<int> Non;
int S;
vector<int> toward[N];
inline void del(int x){
int c=col[x];
scc[c].pop_back();
if(scc[c].size()){
Non.push(scc[c][scc[c].size()-1]);
}else{
for(size_t i=0;i<toward[c].size();i++){
int v=toward[c][i];
deg[v]--;
if(deg[v]==0)Non.push(scc[v][scc[v].size()-1]);
}
}
}
int main()
{
cin >> n >> m;
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
adde(u,v);
}
for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
for(int i=1;i<=cnt;i++){
if(col[from[i]]!=col[to[i]]){
deg[col[to[i]]]++;
toward[col[from[i]]].push_back(col[to[i]]);
}
}
for(int i=1;i<=cn;i++)if(!deg[i]){
Non.push(scc[i][scc[i].size()-1]);
}
S = Non.front();Non.pop();
while(!Non.empty()){
int t = Non.front(); Non.pop();
int ret = query(S,t);
if(ret==1){
del(t);
}else{
del(S);
S=t;
}
}
cout << "! " << S << endl;
}