3799. 【NOIP2014模擬8.22】青蛙神 (Standard IO)
Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits
Description
Input
輸入第1行包含兩個整數N,M。
第2到M+1行每行包含三個整數Ui,Vi,表示有一條Ui與Vi的單向道路。
Output
一行1個整數,表示答案。
Sample Input
6 7 4 2 5 2 2 1 5 1 5 3 3 6 2 3
Sample Output
4 樣例解釋: 4條路徑分別是(1->1),(4->4),(2->3->6),(4->2->3->6)
Data Constraint
對於30%的數據,N<=10。
對於100%的數據,1<=N<=90,0<=M<=8000
數據保證最終答案在64位整型(long long/int64)範圍內。
Source / Author: 常州高級中學NOIP2014夏令營 qingwashen
題解:
看到DAG, 想到拓撲排序。
排完就可以DP了。
一開始。
設f[i][s]表示i點乘積爲s的方案數, 轉移顯然。
後來
s太大了。
一個數A = b * 完全平方數
這樣我們存b就行了。
這不是能狀壓麼?
100以內24個質數, 好似不行。
發現47後面的不需要了, 因爲他像根比他大的構成完全平方數, 至少是90+, 可n只有90.
那麼只剩14個了。
然後狀壓。
反思:
唉。
僞AC題目。
考場錯誤1:拓撲排序後, 用了拓撲編號而不是原來的編號。
2.對於一道狀壓題, 沒有規劃好二進制數每一位的權值。
#include<bits/stdc++.h>
#define open(x) freopen(x".in", "r", stdin);freopen(x".out", "w", stdout)
#define mem(a, b) memset(a, b, sizeof(a))
#define mcy(a, b) memcpy(a, b, sizeof(a))
#define pf printf
#define sf scanf
#define fo(i, a, b) for( ll i = a; i <= b; ++i)
#define fown(i, a, b) for( ll i = a; i >= b; --i)
#define em(p, x) for(ll p=tail[x];p;p=e[p].fr)
#define ll long long
#define wt(a, c, d, s) fo(i, c, d) pf((s), a[i]); puts("")
#define rd(a, c, d) fo(i, c, d) in(a[i])
#define N 100
#define inf 2147483647
#define Ss 32800
#define mod (ll)(1e9 + 7)
using namespace std;
template<class T>
T in(T &x) {
x=0;
char ch = getchar(); ll f = 0;
while(ch < '0' || ch > '9') f |= ch == '-', ch = getchar();
while(ch >= '0' && ch <= '9') x = (x<<1) + (x<<3) + ch - '0', ch = getchar();
x = f ? -x : x;
return x;
}
struct str {
ll num[20];
str() {mem(num, 0);}
}F[Ss];
str operator -(str a, str b) {
str ret;
fo(i, 1, 19) if(b.num[i]&1) ret.num[i] = a.num[i] ^ 1;
else ret.num[i] = a.num[i] ^ 0;
return ret;
}
ll e[N][N], r[N];
ll n, m, f[N][Ss], pri[N], len = 0;
int id[N];
ll l[N], ans;
void tp() {
ll i = 0, j = 0;
fo(i, 1, n) if(r[i] == 0 )l[++j] = i;
while(i++ < j) {
ll u = l[i];
fo(v, 1, n) if(e[u][v]) {
r[v]--;
if(r[v] == 0 ){
l[++j] = v;
}
}
}
}
str fj(ll x) {
str ret;
fo(i, 1, len) if(x % pri[i] == 0 ){
while(x % pri[i] == 0 ) {
x /= pri[i];
ret.num[i]++;
}
}
return ret;
}
ll ss(ll x) {
ll up = sqrt(x);
fo(i, 2, up) if(x % i == 0 ) return 0;
return 1;
}
int S = 0, bk[Ss];
map<ll, int> s;
void init() {
fo(i, 2, n / 2) if(ss(i))pri[++len] = i;
S = 1 << len;
fo(i, 0, S) {
int tmp = i, ret = 1, use = 1;
while(tmp) {
if(tmp&1) ret*=pri[use];
use++;
tmp >>= 1;
}
bk[i] = ret;
s[ret] = i;
}
}
ll deal(str x) {
ll ret = 0;
fown(i, 19, 1) ret = ret * 2 + (x.num[i] & 1);
return ret;
}
void dp() {
fown(i, n, 1)
{
if(ss(l[i]) && l[i] > n / 2) continue;
str I = fj(l[i]);
int st = deal(I);
f[l[i]][st] = 1;
fo(j, 0, S) {
int id = j ^ st;
fo(k, 1, n) {
if(e[l[i]][k]) f[l[i]][j] += f[k][id];
}
if(j == 0) ans += f[l[i]][j];
}
}
}
int main() {
open("souvenir");
in(n), in(m);
fo(i, 1, m) {
int u, v;
in(u), in(v);
e[u][v] = 1;
r[v]++;
}
init();
tp();
dp();
pf("%lld\n", ans);
return 0;
}
O(n^2*2^15);