2018hdu多校第七場
其實這場兩個隊友點醒了我,就是我和另一個隊友的思考風格是,喜歡想出一個思路來,然後根據各種情況分分分分,ifelseifelse,把情況考慮完,但是昨天另一個隊友我倆想h的時候,我枚舉了一下情況,他說太麻煩,就不行,我當時有點無語,他非要再想一個全部的方法不用考慮分情況那種,結果事實證明,這樣還是不錯的。
如果當時我們矩陣那個題能夠這樣再多想想,可能會有更好的,更清晰更具有包含性的寫法,就不用寫那麼長,也不好查bug。
H題Traffic Network in Numazu
樹鏈剖分,思路是去掉一條邊,然後列舉要不要過這個邊的兩個端點,然後取最小。
網上找的板子,跟隊友找了很久很久的bug,就是不明白哪裡錯了。
後來發現居然是陣列開小了????? 但是不明白到底哪裡開小了,需要陣列再開大一倍;
ps:xyk直接把題目輸入的最後一條邊當做環中的一條邊去掉,然後就AC了,這分分鐘hack掉啊,這資料真滴秀,秀的我,,,
程式碼如下:
#include <stdio.h> #include <iostream> #include <string.h> using namespace std; #define N 100000+100 #define L(x) (x<<1) #define R(x) (x<<1|1) #define Mid(x,y) ((x+y)>>1) #define ll __int64 struct Edge { ll from, to, dis,nex; bool yes; } edge[N<<1]; ll c[N]; struct note { ll u,v; ll len; note() {} note(ll u,ll v,ll len):u(u),v(v),len(len) {} } aa[N]; int found(ll x) { if(c[x]==x) return x; else return c[x]=found(c[x]); } bool same(ll x,ll y) { return found(x)==found(y); } void unit(ll x,ll y) { x=found(x); y=found(y); if(x==y) return; c[x]=y; } ll head[N], edgenum; ll huan; ll dis[N]; void addedge(ll u, ll v, ll d) { Edge E= {u,v,d,head[u],false}; edge[edgenum] = E; head[u] = edgenum++; } ll son[N]; ll top[N]; ll fp[N]; ll p[N]; ll siz[N]; ll dep[N]; ll fa[N]; ll tree_id; void dfs(ll u, ll father, ll deep) { fa[u] = father; dep[u] = deep; siz[u] = 1; for(ll i = head[u]; ~i; i = edge[i].nex) { ll v = edge[i].to; if(v == father)continue; dfs(v, u, deep+1); siz[u] += siz[v]; if(son[u] == -1 || siz[son[u]]<siz[v])son[u] = v; dis[v] = edge[i].dis; edge[i].yes = true; } } void getpos(ll u, ll toppos) { p[u] = tree_id++; fp[p[u]] = u; top[u] = toppos; if(son[u] == -1)return; if(u==0)getpos(son[u],son[u]); else getpos(son[u], toppos); for(int i = head[u]; ~i; i = edge[i].nex) { int v = edge[i].to; if(v == fa[u] || v == son[u])continue; getpos(v,v); } } struct node { ll l, r; ll sum; } tree[N*8]; void updata_up(ll id) { tree[id].sum = tree[L(id)].sum+tree[R(id)].sum; } void build(ll l, ll r, ll id) { tree[id].l = l, tree[id].r = r; tree[id].sum = 0; if(l == r)return ; int mid = Mid(l,r); build(l,mid,L(id)), build(mid+1,r,R(id)); } void updata(ll pos, ll val, ll id) { if(tree[id].l == tree[id].r) { tree[id].sum = val; return; } ll mid = Mid(tree[id].l,tree[id].r); if(pos <= mid)updata(pos, val, L(id)); else updata(pos, val, R(id)); updata_up(id); } ll query(ll l, ll r, ll id) { if(l <= tree[id].l && tree[id].r <= r)return tree[id].sum; ll mid = Mid(tree[id].l, tree[id].r); ll ans = 0; if(l <= mid)ans+=query(l,r,L(id)); if(r > mid)ans+=query(l,r,R(id)); return ans; } ll Query(ll x,ll y) { ll f1 = top[x], f2 = top[y]; ll ans = 0; while(f1 != f2) { if(dep[f1]<dep[f2])swap(f1,f2),swap(x,y); ans += query(p[f1],p[x],1); x = fa[f1]; f1 = top[x]; } if(dep[x] > dep[y])swap(x,y); return ans + query(p[x],p[y],1) - query(p[x],p[x],1);; } void change(ll pos, ll val) { Edge &E = edge[pos<<1]; if(E.yes == false) E = edge[pos<<1|1]; E.dis = val; updata(p[E.to], val, 1); } ll n, m; void init() { memset(head, -1, sizeof(head)), edgenum = 0; memset(son, -1, sizeof(son)); for(int i=0; i<=n; i++) c[i]=i; tree_id = 1; } int main() { int TT; scanf("%d",&TT); while(TT--) { ll i, j, u, v, d; scanf("%I64d %I64d",&n,&m); init(); for(i = 1; i <= n; i++) { scanf("%I64d %I64d %I64d",&u,&v,&d); if(!same(u,v)) { addedge(u,v,d); addedge(v,u,d); unit(u,v); } else huan=i; aa[i]=note(u,v,d); } dfs(1,1,0); getpos(1,1); build(1,n,1); updata(p[1],0,1); for(i = 2; i <= n; i++) updata(p[i],dis[i],1); while(m--) { scanf("%I64d %I64d %I64d",&d,&u,&v); if(d == 0) { if(u<huan) change(u-1,v); else if(u==huan) aa[huan].len=v; else { u--; change(u-1,v); } } else { ll z1=Query(aa[huan].u,v)+Query(u,aa[huan].v); ll z2=Query(u,aa[huan].u)+Query(aa[huan].v,v); ll zz=min(z1,z2)+aa[huan].len; ll hh=Query(u,v); printf("%I64d\n",min(zz,hh)); } } } return 0; }
E題 (當時不會)
思路:
根據尤拉函式性質,
如果a中有一質因子p且冪為a1, 如果在b中為a2
則phi(ab) = (p-1)p^(a1+a2-1) , phi(a) *phi(b) = (p-1)*P^(a1-1) * (p-1)*p^(a2-1)
所以 gu(a,b) = p/(p-1)
如果a1 = 0 賊gu(a,b) = 1 ,, a2 = 0,gu(a,b) = 1;
綜上,gu(a,b) = gcd(a,b) /phi( gcd(a,b) );
dls那個容斥甚好,甚好
(n,m)中 i | x 的數目為 f(i) = (n/x) *(m/x) ;
n那麼(n,m)中i == x 的數目為 d[i] = f[i] - sum( g(num * d)| num>=2) )
程式碼:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
//ll gcd(ll a,ll b)
//{
// return b?gcd(b,a%b):a;
//}
//// head
long long inv[maxn];
long long f[maxn];
long long euler[maxn];
void init()
{
euler[1] = 1;
for(int i=2;i<maxn;i++)
euler[i]=i;
for(int i=2; i<maxn; i+=2)
euler[i]/=2;
for(int i=3;i<maxn;i+=2)
if(euler[i]==i)
for(int j=i;j<maxn;j+=i)
euler[j]=euler[j]/i*(i-1);
}
int main()
{
init();
int n,m,mod;
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&mod);
if (n>m) swap(n,m);
inv[1]=1;
for (int i=2; i<=n; i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
long long ans =0;
for(int i=n; i>=1; i--)
{
f[i] = (long long)(n/i)*(m/i);
for(int j = i+i; j<=n; j+=i) f[i] -=f[j];
ans = (ans + f[i] %mod * i %mod * inv[euler[i]]% mod)%mod;
}
printf("%lld\n",ans);
}
}
J Sequence 矩陣快速冪,
思路是一樣的,關於實現的話,,,
看了看標程,哎,想想隊友那程式碼,瞬間覺得我們還有很長的路要走。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
using namespace std;
const long long mod=1e9+7;
struct jz
{
long long num[3][3];
jz() { memset(num,0,sizeof(num)); }
jz operator*(const jz &P)const
{
jz ans;
for(int k=0;k<3;k++)
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
ans.num[i][j]=(ans.num[i][j]+num[i][k]*P.num[k][j]%mod)%mod;
return ans;
}
}COE,ans,unit;
int T_T;
long long A,B,C,D,P,n;
jz pOw(jz X,long long m)
{
jz ans;
for(ans=unit;m;m>>=1,X=X*X)
if(m&1)
ans=ans*X;
return ans;
}
void init(long long A,long long B,long long C,long long D,long long x)
{
COE.num[0][0]=0;
COE.num[0][1]=1;
COE.num[0][2]=0;
COE.num[1][0]=C;
COE.num[1][1]=D;
COE.num[1][2]=x; // this element need to be changed each step.
COE.num[2][0]=0;
COE.num[2][1]=0;
COE.num[2][2]=1;
return;
}
int main()
{
for(int i=0;i<3;i++) unit.num[i][i]=1;
scanf("%d",&T_T);
while(T_T--)
{
scanf("%lld%lld%lld%lld%lld%lld",&A,&B,&C,&D,&P,&n);
if(n==1) printf("%lld\n",A);
else if(n<P)
{
ans.num[0][0]=A;
ans.num[1][0]=B;
ans.num[2][0]=1;
for(long long i=3;i<=n;i=P/(P/i)+1)
{
init(A,B,C,D,P/i);
if(n<=P/(P/i)) COE=pOw(COE,n-i+1);
else COE=pOw(COE,P/(P/i)+1-i);
ans=COE*ans;
}
printf("%lld\n",ans.num[1][0]);
}
else if(P<=n)
{
ans.num[0][0]=A;
ans.num[1][0]=B;
ans.num[2][0]=1;
for(long long i=3;i<=P;i=P/(P/i)+1)
{
init(A,B,C,D,P/i);
COE=pOw(COE,P/(P/i)+1-i);
ans=COE*ans;
}
init(A,B,C,D,0);
COE.num[1][2]=0;
COE=pOw(COE,n-max(P,2LL));
ans=COE*ans;
printf("%lld\n",ans.num[1][0]);
}
}
return 0;
}
K - Swordsman
要用到輸入掛。》》》
有點秀,沒來的及想這個題,dls的思路
(聽人唸叨銀行家演算法,哈哈哈)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
namespace fastIO {
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x) {
char ch;
while(blank(ch = nc()));
if(IOerror) return;
for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
struct node
{
int x;
int id;
node(int xx=0,int idd=0)
{
x = xx;
id = idd;
}
bool operator<(const node& s)const
{
return x<s.x;
}
bool operator==(const node &s)const
{
return x==s.x;
}
};
vector<node> a[6];
int vis[maxn];
int pos[6];
int s[6];
queue<int> q;
int b[maxn][6];
int main()
{
//freopen("1.in", "r", stdin);
// freopen("s.txt", "w", stdout);
int n,m,mod;
int T;
//cin>>T;
read(T);
while(T--)
{
int n,k;
int ans = 0;
while(q.size())
q.pop();
memset(pos,0,sizeof(pos));
memset(vis,0,sizeof(vis));
//cin>>n>>k;
read(n); read(k);
for(int i=0; i<=k; i++)
a[i].clear();
for(int i=0; i<k; i++)
//cin>>s[i];
read(s[i]);
for(int i=0; i<n; i++)
{
for(int j=0; j<k; j++)
{
int x;
// cin>>x;
read(x);
a[j].push_back(node(x,i));
}
for(int j=0; j<k; j++)
//cin>>b[i][j];
read(b[i][j]);
}
for(int i=0; i<k; i++)
{
sort(a[i].begin(),a[i].end());
int t = upper_bound(a[i].begin(),a[i].end(),node(s[i])) - a[i].begin();
for(int j=pos[i]; j<t; j++)
{
int t = a[i][j].id;
vis[t]++;
if(vis[t]>=k)
{
q.push(t);
ans++;
vis[t] = -1e5;
}
}
pos[i] = t;
}
while(1)
{
while(q.size())
{
int d =q.front();
q.pop();
for(int i=0; i<k; i++)
s[i] += b[d][i];
}
int ok = 0;
if(ans == n)
break;
for(int i=0; i<k; i++)
{
int t = upper_bound(a[i].begin(),a[i].end(),node(s[i])) - a[i].begin();
for(int j=pos[i]; j<t; j++)
{
int t = a[i][j].id;
vis[t]++;
if(vis[t]>=k)
{
q.push(t);
ans++;
vis[t] = -1e5;
}
}
pos[i] = t;
}
if(q.empty())
break;
}
printf("%d\n",ans);
for(int i=0; i<k; i++)
{
if(i!=0)
printf(" ");
printf("%d",s[i]);
}
cout<<endl;
}
}