這題比賽的時候題意就看了半天,看到最後看懂了,感覺是找迴圈但是不知道怎麼處理,也沒再做。比完賽對著標程看才明白這題的做法。
題意是說有兩個陣列a,b,他們之間滿足關係式
因為要求找出相互之間的對應關係的種數,再通過例子,便想著是要找迴圈來找出對應關係。因為a可以和f函式的順序構成關係,所以以a為固定,將b乙個乙個對應進去。比如說假設a0=1,a1=2,a2=3,a3=0,構成乙個迴圈節長度為4的迴圈,且b0=1,b1=0,構成乙個迴圈節長度為2的迴圈,先通過a寫出式子,就可以得到
所以最後的結果就等於所有b的迴圈節的長度乘以有多少這個迴圈節長度的迴圈,也就是cal[0][j]*j,最後再乘有多少這個迴圈節長度的迴圈就可以了。這裡處理的時候可以進行一下優化,對於迴圈節,a的長度一定要比b長,而且b一定是a的因子,所以如果b不是a的因子可以直接跳過。在跑for迴圈的時候,以前篩選的方法可以繼續使用,就是算出sqrt(i),跑迴圈只跑到sqrt即可得出乙個因子,另乙個因子就可直接通過i/j來得到,就不需要全部遍歷搜尋一遍了。
找迴圈節的方法直接用的標程裡提供的方法,寫乙個dfs,從乙個點i開始找,之後再找這個點的下乙個數,也就是a[i](b[i]),每找過乙個點標記一下,最後找到已標記的點則結束遍歷,記錄下來個數。
下面ac**:
#include#include#include#include#includeusing namespace std;
int a[100005];
int b[100005];
int vis[100005];
int cal[5][100005];
const int mod=1000000007;
int dfs(int t,int i,int *c,int k)
vis[t]=1;
dfs(c[t],i+1,c,k);
return 0;
}int main()
{ int case=0;
int n,m;
int i,j;
long long ans;
int lim;
long long t;
while(scanf("%d%d",&n,&m)!=eof)
{memset(vis,0,sizeof(vis));
memset(cal,0,sizeof(cal));
for(i=0;i
HDU 6038 Function(強連通分量)
include include include using namespace std tarjan演算法 對於a和b分別建圖,讓i與ai連邊 i與bi連邊 計算圖強連通分量的個數cnt a,cnt b和各個強連通分量包含點的個數num a,num b 如果num a num b num a num...
HDU 找新朋友
題目大概是小於n的數中有多少個與n互素的數。這裡可以用尤拉公式。函式的值 通式 x x 1 1 p1 1 1 p2 1 1 p3 1 1 p4 1 1 pn 其中p1,p2 pn為x的所有質因數,x是不為0的整數。1 1 唯一和1 互質的數 小於等於1 就是1本身 注意 每種質因數只乙個。比如12 ...
hdu 找新朋友
題目 problem description 新年快到了,豬頭幫協會 準備搞乙個聚會,已經知道現有會員n人,把會員從1到n編號,其中會長的號碼是n號,凡是和會長是老朋友的,那麼該會員的號碼肯定和n有大於1的公約數,否則都是新朋友,現在會長想知道究竟有幾個新朋友?請你程式設計序幫會長計算出來。inpu...